【问题标题】:How to get MinGW GCC to recognize the %zu format specifier for size_t?如何让 MinGW GCC 识别 size_t 的 %zu 格式说明符?
【发布时间】:2021-10-24 06:03:43
【问题描述】:

一张图片胜过一千个字:

我知道如何解决这个问题。但是我如何在 Microsoft 中修复它,这样我什至不会收到警告?

编辑:

  1. 与其他人在评论中指出的相反,这是 Microsoft 系统特有的。我可以在 linux 机器上运行完全相同的代码,在相同版本的 VsCode 中使用相同的配置(tasks.json 和 properties.json),使用相同版本的 gcc,我不会收到这些编译器警告.
  2. 我使用的 C 标准是 c17。
  3. 尝试在与格式相关的函数(如 printf 和 scanf)中使用“%z”(甚至“%ll”)等格式说明符将触发格式编译器警告,即使在完全更新的情况下(截至 2021 年 8 月) Windows 10 操作系统,带有最新的 mingw-64 工具链(特别是 gcc 8.1.0 - 这是这里使用的编译器)。
  4. 图片中显示的“编译器错误”实际上只是被视为错误的格式警告(引用编译器:“ [-Werror=format=] ”)
  5. 谢谢,“@the busybee”。你试图解决这个问题。这确实是一个很好的解决方法,但它会影响开发兼容性。

编辑 2:

在遇到导致实际意外错误的格式不兼容问题(以及在 Windows 上使用 GDB 的高级功能的糟糕经历之后)之后,我决定在 Windows 上永远放弃 GNU。对于 Windows 机器上的 C 跨平台开发,我现在使用 Clang。到目前为止,我对这个决定 100% 满意。感谢所有花时间帮助我的人。

【问题讨论】:

  • 欢迎来到 Stack Overflow。请阅读How to Ask提出一个实际问题 - 告诉我们具体你在问什么,在你写在帖子正文中的文字中我>,not as an image。另外,不要用你的问题来发泄关于公司的问题(尤其是因为如上所述,你甚至没有正确地指责)。
  • 这不是微软的错。这显然是 MinGW 的一个缺点,它不是微软的产品。
  • 除了使用文本而不是图像,请使用提出问题或描述问题的主题(而不仅仅是咆哮)。
  • 它是特定于 MS 的,当你在 OS 上编译时,它包含特定的头文件

标签: c gcc mingw gcc-warning format-specifiers


【解决方案1】:

值得指出的是这里的根本问题,即:严重违反"don't repeat yourself" 原则。我们有一个库函数printf,它在运行时会解析它的格式字符串并尝试打印一些东西。然后我们在 C 编译器中有一段完全不同的代码,它将在编译时解析相同的格式字符串,并警告用户潜在的问题。

在 Windows 下使用 MinGW 时,由于这两个解析器是由两组完全不同的人编写和维护,而他们之间没有任何联系,因此问题变得更加复杂。 (至少在 Linux 下,从事 gcc 工作的人和从事 glibc 工作的人之间有很多协调。)

因此,两个解析器之间对于接受的内容并不完全一致也就不足为奇了。 (确实,如果能达成完美的协议,那将是一个奇迹。)this question 的答案在一定程度上描述了 2012 年的协调有多不完美,而我们在 10 年后仍然不完美。

不完美是游戏的名称,可能没有完美的解决方案。我不得不相信,在 2021 年,微软的 C 运行时库确实支持%zu。但是如果 MinGW 中内置的最新版本 gcc 还没有赶上这个事实,如果它仍然警告 z 修饰符不支持,那么你可能无能为力。您可以向 MinGW 人员发送错误报告,他们最终可能会采取行动,但与此同时,您已经获得了今天需要编译的代码。您可以关闭 -Wformat,但您可能不想(事实上我也不想),因为您可能希望 -Wformat 继续检查您可能犯的其他错误。

我是一个维护大型、成熟、跨平台代码库的团队的一员,尽管它是我非常想使用的理想解决方案,但我们仍然不经常使用 %zu,因为我们仍然不能确定我们使用的每个编译器和每个运行时库都同意它。

我这样说并不是要建议你也放弃 %zu,而只是为了表达我的同情:即使在 2021 年,安全便携地打印 size_t 值仍然非常困难。

【讨论】:

  • 是的,基本上就是这样。关于触发警告的唯一要做的事情就是报告一个错误,似乎......但是关于“变通办法”,是的,@the busybee 提出了一个非常有趣的解决方案,而我自己在cmets对他的建议,已经指出了其他人。谢谢你们。
【解决方案2】:

MinGW 默认使用 Microsoft 运行时库,因此检查 printf() 的格式字符串,因为 MinGW 项目认为 Microsoft 支持它。显然%zu 被视为不受支持,这可能不一定是真的。 (在 Windows 10 上使用 MinGW64 的 GCC 8.1.0 快速检查会显示警告,但有效。)

不过,MinGW 还附带了一组替代实现。要使用它们,请在函数名称前加上 __mingw_(例如 __mingw_printf)。

根据您项目的性质,您可能希望全局使用#define printf __mingw_printf 或使用-D__USE_MINGW_ANSI_STDIO(这将启用所有 printf 系列函数的 MinGW 版本)。

另一个避免警告的选项是对编译器隐藏格式字符串,例如将它放在另一个模块中,或者在运行时构造它。

【讨论】:

  • 非常感谢您的回答。这绝对是“变通办法”之一,但那会使我的代码不可移植(另一种不影响可移植性的变通办法是在没有“-Werror”标志的情况下编译。我也可以下来-将sizeof 输出转换为long unsigned)。无论如何,我赞成你的努力,因为你真的试图解决 Micorsoft 系统中的特定问题并摆脱“编译器警告”,但由于可移植性问题,无法将其标记为已解决。我只是想知道如何更新微软的格式库。
  • 嗯,可移植性始终与通用功能集的大小有关。 "%zu" 似乎不是其中的一部分。 ;-) 但是,您可以有条件地使用#define,否则__USE_MINGW_ANSI_STDIO 不会影响其他目标系统。
  • 谢谢。我认为你提出了很好的观点。 “z”,甚至“ll”(`long long`),格式修饰符应该是跨平台的,安全且易于实现;它们怎么不是,简直让我感到困惑。自 C99 以来,它们是标准格式修饰符,sizeof 函数相当常用。我认为是因为一些“变通方法”(如沮丧)使用起来非常简单,所以这只是被忽视了......我猜(?)。无论如何,错误报告。感谢您的宝贵时间。
  • 显然不支持 %zu 不正确 - MinGW 在这里坏了。 MS supports %zu: "size_t z or I (uppercase i) d, i, o, u, x, or X" 这也不难找到:google.com/search?q=msvc+format+string
  • @AndrewHenle 它是在 Microsoft 上运行的 GNU,但其他编译器(Clang 和 MSVC)工作得很好。忽略警告的问题在于,在 C 语言中,您最终会遇到不可预测的行为。忽略了有关%Lf 的警告,并在编译后出现错误代码......使用 Clangm 重建并重新编译了相同的程序,并且除了没有 -Wformat 之外,代码运行得很好。没有更改源文件中的单个字符。 Mingw-64 在 Windows 上肯定被破坏了(GDB 甚至不允许“记录”或“后退”功能,甚至“tui 模式”)......只是放弃了它。
猜你喜欢
  • 2013-03-14
  • 2020-05-24
  • 2011-03-11
  • 2017-05-06
  • 2021-07-11
  • 2012-11-29
  • 2011-01-08
相关资源
最近更新 更多