尽管使用相同的固定长度数据类型,C 程序在不同的机器上产生不同的结果

Cly*_* B. 37 c windows mingw scanf c99

我在尝试 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;
}
Run Code Online (Sandbox Code Playgroud)

在我的手机(64 位八核 ARN LTE Soc Android 10)上,它工作正常:

Enter x: 1
Enter n: 0
The 0th bit of 1 is: 1
Run Code Online (Sandbox Code Playgroud)

但在我的计算机(64 位 x86 Windows 10)上我得到:

Enter x: 1
Enter n: 0
The 0th bit of 0 is: 0
Run Code Online (Sandbox Code Playgroud)

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

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

Lun*_*din 40

如果您使用的 Windows 编译器使用 Microsoft 不兼容的 CRT(非)标准库,您可能会遇到此问题。即:Visual Studio 或 Mingw64/gcc。

我可以在 Mingw/gcc 上重现它。Microsoft CRT 损坏是一个众所周知的问题,例如不支持 C99 中引入的各种格式说明符。问题似乎在于scanf使用错误的格式说明符进行读取,因为在启用所有警告的情况下进行编译时,我得到:

警告:格式 [-Wformat=] 中存在未知转换类型字符“h”

%hh是位于引擎盖下的内容,SCNu8但编译器只读取到%h并停止在那里。实际调用scanf失败。

您至少可以使用以下命令在 Mingw 中解开 CRT 库:

#define __USE_MINGW_ANSI_STDIO 1
#include <stdio.h>
Run Code Online (Sandbox Code Playgroud)

当我将上述内容添加到您的代码中时,我得到了The 0th bit of 1 is: 1.
没有上面的补丁我得到The 0th bit of 0 is: 0

  • MSVC 显然不支持 C99(并且没有声称支持)。不过,正因为如此,声称(或至少强烈暗示)该问题存在于任何最新的 Microsoft 编译器中是错误的。至于错误修复:这在 MinGW 中很明显。众所周知,MinGW 已经过时了。据我所知:过去 6 年来发布的任何 Microsoft CRT 中都不存在此错误。无论如何,否决票是因为错误信息。 (9认同)
  • 所以你的推理是,某些版本的 Visual Studio(顺便说一句,它没有承诺实现 C99 标准库)很糟糕,因为它没有实现 C99 标准库。正因为如此,Visual Studio 的所有未来版本都很糟糕(包括承诺实现 C99 标准库并兑现这一承诺的 2015+)。这样做时,您会歪曲错误是在 MinGW 中,它使用 Microsoft 的库,**不符合规范**,同样如此。但答案仍然是:*“Microsoft CRT 损坏是一个众所周知的问题”*。 (8认同)
  • @IInspectable 这种不符合项是众所周知的并有记录,我们在网站上有多个关于它的帖子[示例](/sf/ask/3106800371/没有警告-mingw-w64-gcc-7-1)。目前还不清楚为什么 OP 的一致性代码会在 Windows 中变得疯狂,所以如果我不知道 MS CRT 中的这个缺陷,我将永远无法回答。`__USE_MINGW_ANSI_STDIO` 不仅仅是我偶然输入的随机字母,而是一个需要修复此不符合问题的错误的定义。如果 CRT 符合标准,那么为什么有人要编写错误修复程序...... (6认同)
  • @IInspectable Microsoft 编写了 CRT,但 Mingw 的维护者没有编写。同样,我不知道它使用哪个版本的 CRT,但事实是它 1) 是由 Microsoft 编写的,2) 它包含错误。无论使用什么编译器或标准 lib/CRT,都不建议使用具有已知错误的旧版本。而所有这些问题的根源正是 Microsoft 一贯傲慢地拒绝遵循 ISO 9899:1999 等技术 ISO 标准。除了他们之外,行业中的其他人都这样做。这就是我们最终会遇到这样的错误的原因。 (5认同)
  • C 运行时是特定于系统的,因此应该随系统一起提供。但由于微软很久以前就停止在 Windows 中预安装较新版本的动态库(我认为最后一个版本是 1998 年的 6.0),MinGW 默认使用旧版本以实现兼容性,因此您可以使用动态库,而不必使用安装较新运行时的可再发行软件包。它可以选择任何可用版本。 (5认同)
  • @克莱德B。实际上不是编译器的问题,而是标准库的问题。你可以在 Linux 和 Mingw/Windows 中使用相同的 gcc 版本编译它,并得到不同的结果。这是相同的编译器,但它们使用不同的标准库。 (4认同)