不正确的printf格式指定器编译
Incorrect printf format specifier compiles
编译此mcve
#include <stdio.h>
#include <climits>
#include <limits>
int main()
{
unsigned long x = ULONG_MAX;
printf( "1:=%lu - 2:=%lu 3:=%ldn", std::numeric_limits<size_t>::max(), x, x );
}
使用这些GCC/Clang [任何版本]选项-Wall -Werror -pedantic
不会失败。
这是输出:
1:=18446744073709551615 - 2:=18446744073709551615 3:=-1
我期望发生错误,因为我提供了unsigned int
,但格式指定符为signed int
。
使用PowerPC GCC 4.8汇编,如预期的:
错误:格式'%lu'期望类型为"长unsigned int'",但是 参数2具有'unsigned int'[-werror =格式=]
的类型
我的问题是:
为什么GCC/Clang会编译这些格式指定器?对我来说,我会说PowerPC GCC是正确的,因为这是一个严重的标志/未签名的问题,错误的格式指定符显示不正确的结果。
根据GCC(Min 5.0)文档,
-wformat-signedness 如果指定 -wformat ,也要警告格式字符串字符串需要一个无符号的参数,并且该参数已签名,反之亦然。
。 >
此设置不是默认设置,因为标准不要求它。如果您想要的不是标准,则需要使用正确的标志。就您而言,您正在使用 -wformat 通过 -wall ,但不是 -wformat-signedness 。请记住, -wall 并不打开所有警告,只是一个几乎所有人同意的子集。
编译器确实检查了类型安全性,因此,当您删除长期项目时,为什么要警告。除此之外,如果数据没有丢失(例如在int到长到长时间签名或晋升的符号或未签名的标志中,等等),他们可以随意什么都不做。实际上,Clang没有标志检查格式(AFAIK)的标志。
以不合适的方式使用 printf
是不确定行为的实例。实施可以做非常糟糕的事情(包括显然您梦dream以求的事情)。
顺便说一句,使用C ,您最好使用STD :: COUT及其operator <<
,它易于错误。
为什么GCC/Clang会编译这些格式指定器?
大多数情况下,它不会(但是,编译器可能知道printf
和有时优化对其的调用,因为您的<stdio.h>
标头将使用特定的format
功能属性)。在您的情况下,编译器可能会发出对您的标准C库提供的variadic printf
的呼叫。它是不编译格式指定符(只是将字面常数作为第一个参数传递给printf
)。
btw,printf
中size_t
的控制格式字符串是%zu
最终,语言规格没有定义编译器应警告的内容。
- 二叉排序树无法编译
- 编译时未启用intel oneApi CUDA支持
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 在C++标准中做格式好意味着代码可以编译
- 如何设置叮当格式的注释编译指示,以免触及多行doxygen注释?
- C++ 编译错误:gnu_printf是无法识别的格式函数类型
- 自定义 {fmt} 格式化函数,具有编译时格式字符串检查功能
- 不正确的printf格式指定器编译
- 编译用于创建boost.log格式的代码时出错
- 成功地编译成格式的程序是符合标准的
- 在编译时以 static_assert() 格式显示整数
- 一种在编译时用C++根据printf格式检查参数的可移植方法
- 以在编译时和运行时都可用的方式描述C++像素格式信息
- 在调试模式下编译时,丰富的编辑控件格式不起作用
- 使用constexpr进行基本编译时格式字符串检查
- c++ 11编译时调用printf的格式字符串字面值构造
- 编译复杂的(有很多引用的)ASN模式-证书请求格式(RFC4211)
- 当编译时数据格式和类型未知时,C++将数据读入内存
- GCC-如何使用FLV1(又名H.263)、MP3(格式和编解码器)和FLV(容器格式)编译FFMpeg
- 为什么这个格式错误的程序在 g++ 中编译得很好