我用 C99 编写了一个完整的应用程序,并在两个基于 GNU/Linux 的系统上对其进行了彻底的测试。当尝试在 Windows 上使用 Visual Studio 编译它导致应用程序行为异常时,我感到很惊讶。起初我无法断言出了什么问题,但我尝试使用 VC 调试器,然后我发现fscanf()
在stdio.h
.
以下代码足以说明问题:
#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;
}
假设file.bin正好包含512\0256\0128\0
:
$ hexdump -C file.bin
00000000 35 31 32 00 32 35 36 00 31 32 38 00 |512.256.128.|
现在,当在 Ubuntu 机器上在 GCC 4.8.4 下编译时,生成的程序会按预期读取数字并打印512, 256, 128
到标准输出。
在 Windows 上使用 MinGW 4.8.1 编译它会得到相同的预期结果。
但是,当我使用 Visual Studio Community 2015 编译代码时,似乎有很大的不同;即,输出为:
512, 56, 28
如您所见,尾随的空字符已被 使用fscanf()
,因此fgetc()
捕获并丢弃对数据完整性至关重要的字符。
注释掉这些行使fgetc()
代码在 VC 中工作,但在 GCC(可能还有其他编译器)中破坏它。
这里发生了什么,如何将其转换为可移植的 C 代码?我是否遇到了未定义的行为?请注意,我假设 C99 标准。