为什么gcc -Wformat不会对unsigned int的printf %d进行警告?

10

以下程序具有未定义的行为:

#include <stdio.h>

int main(void)
{
    unsigned int x = -100; // This is fine, becomes UINT_MAX - 100
    printf("%d\n", x); // This is undefined behavior.
    return 0;
}
C99标准中 %d 期望的是int类型参数。C99标准7.19.6.1p9表明:"如果任何一个参数与相应的转换说明符类型不匹配,其行为是未定义的"。然而,gcc的-Wformat(包括-Wall选项)不会对上述程序发出警告,这是为什么?这是一个错误还是故意忽略的?从gcc手册可以看出:
-Wformat

检查对 "printf""scanf" 的调用等,确保提供的参数与指定的格式字符串具有适当的类型,并且在格式字符串中指定的转换是合理的。


2
C99 6.3.1.3p3 表示将无符号数转换为有符号数是实现定义的。 - jxh
@user315052:没有转换;x(一个unsigned int对象)的表示被解释为它是int类型。 - Keith Thompson
@KeithThompson:我认为这是因为C99 7.15.1.1p2的最后一句话,它在通过va_arg宏转换参数类型时对有符号/无符号进行了例外处理。 - jxh
@user315052:我刚刚读了那段话,它并没有暗示有转换的存在。 - Keith Thompson
编译器不必警告标准中的任何UB。如果这个编译器被编写成在这种情况下表现良好,那就没有问题。 - M.M
显示剩余4条评论
1个回答

9
我的最佳猜测是警告被跳过,因为UB可能是由而不仅仅是类型所引发的。 va_arg 允许有符号性不匹配,只要该值可在有符号和无符号类型中表示。然而,printf 和其他相关函数没有用 va_arg 规定,标准规定任何类型不匹配都会导致 UB,但这可能是标准中的一个错误。否则,printf("%x",1); 将会引发 UB。请参见我在此主题上的问题:

printf("%x",1) 是否会引发未定义行为?


谢谢。这是有道理的,因为6.2.5p6要求int和unsigned int使用相同的存储量。尽管在无符号数上使用printf %d在技术上是未定义的,但没有什么明显的原因导致它引起实际问题。 - Chris Young
标准并没有说printf()使用<stdarg.h>,但是你可以构造一个指向printf()函数的指针并通过它调用,这意味着参数传递机制至少有一些共性。 - Keith Thompson
3
现在的GCC 5.0有一个警告:-Wformat-signedness (由-Wformat启用)。 - cremno
在这里进行实验http://rextester.com/live/CCQJKP79309,建议使用-Wformat-signedness,但不包括在-Wformat中。 - MK.
作为一个独立选项的整个意义在于它不会。 - R.. GitHub STOP HELPING ICE

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