Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

#574 Strange behaviour of fscanf

closed-invalid
Danny Smith
gcc (462)
2004-05-18
2004-05-18
Maciej Kozinski
No

This seems like a bug: fscanf seems to set a
variable to zero. But the variable is NOT USED in
fscanf call. I'm not quite sure whether I did
everything ok (my knowledge of C is rather basic),
but I think the variable shouldn't be reset there.
I have discovered this strange behaviour writing
simple program in Dev-C++ 4.9.8 with mingw. The
program reads hexadecimal digits from a file to load
them into memory and sums for checksum. After
calling fascanf one of the variables (prsum) is set to
zero. Comment out line with fscanf to see what
happens, if there is no fscanf.
There goes a code (critical lines emphasized via
comments):

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

#define MEMSIZE 4096

unsigned char mem[MEMSIZE];

void display (int min, int max) {
unsigned int x, y;
if ((min >= max) || (min <0) || (min > MEMSIZE) ||
(max<1) || (max > MEMSIZE)) {
printf ("Invalid minimum or maximum range or
relation.\n");
return;
}
unsigned int minrow, maxrow;
minrow = min / 16;
maxrow = max / 16;
printf ("Address ");
for (x = 0; x <= 15; x++) {
printf ("%3x", x);
}
printf ("\n\n");
for (x = minrow; x <= maxrow; x++ ) {
printf ("%7.3x ", x*16);
for (y = 0; y <= 15; y++) {
printf ("%-3.2x", mem[x*16+y]);
}
printf ("\n");
}
}

int load (const char * fname, unsigned int *
load_addr, unsigned int * program_size, unsigned int
* start_addr) {
FILE * f;
unsigned int x;
unsigned int i;
unsigned int prsum;
unsigned char checksum;
if (!(f=fopen (fname, "r"))) {
printf ("Can't open file %s\n",fname);
return (0);
}
fscanf (f, "%x", load_addr);
fscanf (f, "%x", program_size);
if (*load_addr + *program_size > MEMSIZE) {
printf ("Invalid load adress and program size -
program out of memory\n");
return (0);
}
fscanf (f, "%x", start_addr);
for (i = 0; i < *program_size; i++ ) {
fscanf (f, "%x", &x);
printf ("%x\n",x);
mem [*load_addr + i] = x;
prsum += x;
printf ("Sum: %d\n", prsum);
}
/* LOOK HERE */
printf ("Sum before fscanf: %d\n", prsum);
/* comment this line out */
fscanf (f, "%x", & checksum);
fclose (f);
/* AND HERE */
printf ("Sum after fscanf: %d\n", prsum);
if ((prsum + checksum) % 256 != 0 ) {
printf ("Invalid checksum! %x \n", prsum);
printf ("Should be: %d\n", prsum % 256);
return (0);
}

return (1);
}

int main () {
char * c;
unsigned int loadaddr, size, start;
load ("emu.hex", & loadaddr, & size, & start);
display (loadaddr,loadaddr + size);
while (!(*c = getchar())){
};
return 0;
}

Here is the data:

abc
006
10
ab
92
12
11
ce
5d
1f

And there is compiler version:

C:\WINDOWS>gcc -v
Reading specs from D:/CPP/BIN/../lib/gcc-lib/m
Configured with: ../gcc/configure --with-gcc -
mingw32 --target=mingw32 --prefix=/mingw --ena
-languages=f77,c++,objc,ada --disable-win32-re
Thread model: win32
gcc version 3.2 (mingw special 20020817-1)

I'll be glad to know something is to be improved ;-)

Best regards,
Maciej

Discussion

  • Earnie Boyd
    Earnie Boyd
    2004-05-18

    • status: open --> closed-invalid
     
  • Logged In: YES
    user_id=757803

    That's probably not the problem of text mode, which is
    rather know to me. The problem IS NOT fscanf didn't read
    &checksum properly. It did. The problem IS after calling
    fscanf (f, format, &checksum) the other variable - prsum -
    has become 0 from value of 651 !!! After commenting out
    line of "fscanf (..., &checksum) prsum didn't change. I've
    changed file opening mode to "rb", but the result is the
    same - still changing prsum to 0 :(

     
  • Logged In: YES
    user_id=757803

    Helped something like this:

    unsigned int prsum = 0;
    int c;
    unsigned char checksum;

    where c is not used at all. prsum remains 651 after
    calling fscanf (..., &checksum). Probably fscanf operates
    at memory of variables declared next to checksum.

     
  • Logged In: YES
    user_id=757803

    Also reordering variables resolves this problem:

    FILE * f;
    unsigned int prsum = 0;
    unsigned int x;
    unsigned int i;
    unsigned char checksum;

    Both x and i are not used at the end of the function, so it
    does not matter in the progra. But this is probably a bug.

     
  • Earnie Boyd
    Earnie Boyd
    2004-05-18

    Logged In: YES
    user_id=15438

    You need to try a newer version of GCC to see if the problem
    still exists. I've reassigned this to Danny since it
    appears to be a compiler issue.

    Earnie

     
  • Earnie Boyd
    Earnie Boyd
    2004-05-18

    • assigned_to: earnie --> dannysmith
    • labels: 456608 --> gcc
    • status: closed-invalid --> open
     
  • Luke Dunstan
    Luke Dunstan
    2004-05-18

    • status: open --> closed-invalid
     
  • Luke Dunstan
    Luke Dunstan
    2004-05-18

    Logged In: YES
    user_id=30442

    Your code is incorrect. If you read the fscanf documentation
    you will find that if you pass the %x format specifier then the
    argument must be a pointer to an int. Compiling with -Wall
    gives:

    scanf.c: In function `load':
    scanf.c:65: warning: unsigned int format, different type arg
    (arg 3)

     
  • Logged In: YES
    user_id=757803

    Luke,

    tnx for solution. I have used K&R "Ansi C" for reference -
    there is such a quote that you MAY use h or l modificator
    to format string, but it didn't points out that it is
    mandatory. So I was convinced it is really compiler
    problem.
    Thanks again and sorry for bothering You - it's my fault.

    M.