不正确的printf格式指定器编译

Incorrect printf format specifier compiles

本文关键字:编译 格式 printf 不正确      更新时间:2023-10-16

编译此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,printfsize_t的控制格式字符串是%zu

最终,语言规格没有定义编译器应警告的内容。