使用相同的固定长度数据类型,但在不同的计算机上运行 C 程序会产生不同的结果。

37

我在尝试使用inttypes.h时编写的简单程序:

#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>

bool get_bit(uint32_t x, uint8_t n) {
    x >>= n;
    return x & 1;
}

int main() {
    uint32_t x;
    uint8_t n;

    printf ("Enter x: ");
    scanf("%"SCNu32, &x);

    printf ("Enter n: ");
    scanf("%"SCNu8, &n);

    printf("The %"PRIu8"th bit of %"PRIu32" is: %d", n, x, get_bit(x, n));
    return 0;
}

在我的手机上(64位八核ARN LTE Soc Android 10),它可以很好地工作:

Enter x: 1
Enter n: 0
The 0th bit of 1 is: 1

但是在我的电脑上(64位x86 Windows 10),我得到以下结果:

Enter x: 1
Enter n: 0
The 0th bit of 0 is: 0

将bool更改为uint8_t不会影响它。

编辑:我尝试使用MinGW-w64 GCC C99和C17进行编译。


6
你确定输入成功了吗?一定要检查scanf函数的返回值。 - user694733
3
在我成功重现它之前,我也持怀疑态度。必须使用被Microsoft CRT感染的编译器才能重现它,否则你无法重现。 - Lundin
1个回答

40

如果你使用微软的非标准库CRT(nonstandard library)编译器,例如Visual Studio或Mingw64/gcc,那么你可能会遇到这个问题。我在Mingw/gcc上也遇到了这个问题。众所周知,Microsoft CRT存在问题,例如不支持C99引入的各种格式说明符。看起来问题出在scanf读取时使用了错误的格式说明符,因为当启用所有警告进行编译时,我得到了以下警告:

warning: unknown conversion type character 'h' in format [-Wformat=]

%hh实际上是SCNu8背后的内容,但编译器只读到%h就停止了。这导致scanf调用失败。

你可以通过使用以下方法在Mingw中解决CRT库的问题:

#define __USE_MINGW_ANSI_STDIO 1
#include <stdio.h>
当我的代码加入上述内容后,输出为The 0th bit of 1 is: 1。如果没有上述补丁,则输出The 0th bit of 0 is: 0

6
这个非符合性问题很常见并有记录,我们在网站上有多篇关于它的文章例子。不明显为什么OP的符合代码在Windows中会出错,所以如果我不知道MS CRT中的这个缺陷,我就无法回答。__USE_MINGW_ANSI_STDIO不是我意外键入的随机字母,而是一个定义,调用了这个非符合性问题的错误修复程序。如果CRT符合规范,那么为什么会有人写一个错误修复程序... - Lundin
9
显然,MSVC不支持C99(也没有声称支持)。但仅仅因为这个原因,在任何最近的Microsoft编译器中声称(或至少强烈暗示)存在问题是错误的。至于错误修复:明显在MinGW中。众所周知,MinGW已经彻底过时。就我所看到的:这个bug在过去6年内发货的任何Microsoft CRT中都不存在。无论如何,这次负评是因为提供了错误信息。 - IInspectable
8
你的推理是,某个版本的Visual Studio(顺便提一下,它并没有承诺实现C99标准库)很糟糕,因为它没有实现C99标准库。正因如此,所有未来的Visual Studio版本都很糟糕(包括承诺实现C99标准库并兑现承诺的2015+版本)。这样做会误传错误在于MinGW中使用了微软的库,并且不符合规范。但回答仍然是: “众所周知,Microsoft CRT存在问题”。 - IInspectable
5
@IInspectable提到,CRT是由Microsoft编写的,而Mingw的维护者并没有编写它。我不知道它使用的是哪个版本的CRT,但事实是,它1)由Microsoft编写,2)其中包含有缺陷的代码。无论使用哪种编译器或标准库/CRT,都不建议使用已知存在缺陷的旧版本。而所有这些问题的根源是Microsoft持久而傲慢地拒绝遵循技术ISO标准,包括ISO 9899:1999。在该行业中,除了他们之外,其他人都会遵循这些标准。这就是我们为什么会遇到这样的软件缺陷。 - Lundin
5
C运行时库是特定于系统的,因此应该随系统一起提供。但由于微软很久之前就停止预装较新版本的动态链接库(我认为最后一个是1998年的6.0版),MinGW默认使用古老的版本以确保兼容性,这样你就可以使用动态链接库而无需创建安装程序,并安装新的运行时库可再发行包。它有一个选项可以选择任何可用的版本。 - Jan Hudec
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接