I wrote a complete application in C99 and tested it thoroughly on two GNU/Linux-based systems. I was surprised when an attempt to compile it using Visual Studio on Windows resulted in the application misbehaving. At first I couldn't assert what was wrong, but I tried using the VC debugger, and then I discovered a discrepancy concerning the fscanf()
function declared in stdio.h
.
The following code is sufficient to demonstrate the problem:
#include <stdio.h>
int main() {
unsigned num1, num2, num3;
FILE *file = fopen("file.bin", "rb");
fscanf(file, "%u", &num1);
fgetc(file); // consume and discard \0
fscanf(file, "%u", &num2);
fgetc(file); // ditto
fscanf(file, "%u", &num3);
fgetc(file); // ditto
fclose(file);
printf("%d, %d, %d\n", num1, num2, num3);
return 0;
}
Assume that file.bin contains exactly 512\0256\0128\0
:
$ hexdump -C file.bin
00000000 35 31 32 00 32 35 36 00 31 32 38 00 |512.256.128.|
Now, when being compiled under GCC 4.8.4 on an Ubuntu machine, the resulting program reads the numbers as expected and prints 512, 256, 128
to stdout.
Compiling it with MinGW 4.8.1 on Windows gives the same, expected result.
However, there seems to be a major difference when I compile the code using Visual Studio Community 2015; namely, the output is:
512, 56, 28
As you can see, the trailing null characters have already been consumed by fscanf()
, so fgetc()
captures and discards characters that are essential to data integrity.
Commenting out the fgetc()
lines makes the code work in VC, but breaks it in GCC (and possibly other compilers).
What is going on here, and how do I turn this into portable C code? Have I hit undefined behavior? Note that I'm assuming the C99 standard.