根据C标准(6.5.2.2第6段):
如果表示所调用函数的表达式具有不包括原型的类型,则对每个参数执行整数提升,如果参数的类型为float,则将其提升为double。这些被称为默认参数提升。如果参数的数量与参数的数量不相等,则行为未定义。如果使用包含原型的类型定义函数,且原型以省略号 (,...) 结尾或在推广后的参数类型与参数类型不兼容,则行为未定义。如果使用不包含原型的类型定义函数,并且推广后的参数类型与推广后的参数类型不兼容,则行为未定义,但以下情况除外:
一个提升的类型是有符号整数类型,另一个提升的类型是相应的无符号整数类型,并且该值在两种类型中均可表示; 这两种类型都是限定或未限定版本的字符类型或void指针。
因此,通常情况下,只要传递的值适合于两种类型,就可以将int传递给期望unsigned int(反之亦然)的可变参数函数,但是,printf的规范(7.19.6.1第9段)如下:
如果转换说明符无效,则行为未定义。如果任何参数不是相应转换说明符的正确类型,则行为未定义。
没有为signed/unsigned不匹配做出例外。
这是否意味着printf(“%x”,1)会引发未定义的行为?
如果表示所调用函数的表达式具有不包括原型的类型,则对每个参数执行整数提升,如果参数的类型为float,则将其提升为double。这些被称为默认参数提升。如果参数的数量与参数的数量不相等,则行为未定义。如果使用包含原型的类型定义函数,且原型以省略号 (,...) 结尾或在推广后的参数类型与参数类型不兼容,则行为未定义。如果使用不包含原型的类型定义函数,并且推广后的参数类型与推广后的参数类型不兼容,则行为未定义,但以下情况除外:
一个提升的类型是有符号整数类型,另一个提升的类型是相应的无符号整数类型,并且该值在两种类型中均可表示; 这两种类型都是限定或未限定版本的字符类型或void指针。
因此,通常情况下,只要传递的值适合于两种类型,就可以将int传递给期望unsigned int(反之亦然)的可变参数函数,但是,printf的规范(7.19.6.1第9段)如下:
如果转换说明符无效,则行为未定义。如果任何参数不是相应转换说明符的正确类型,则行为未定义。
没有为signed/unsigned不匹配做出例外。
这是否意味着printf(“%x”,1)会引发未定义的行为?
printf("%d",(char)1);
呢?printf
的描述并没有说它必须是正确类型的整数提升后的参数,而是说参数本身必须是正确类型。我们应该得出结论,它也是6.5.2.2/6这部分的一个例外吗? - Steve Jessopprintf
是未定义的行为,而你的引用涉及到在没有原型的情况下进行的调用。然而,根据6.5.2.2/7,相同的参数提升适用于varargs的参数,尽管这并没有说明有关有符号/无符号兼容性的内容。所以也许你是完全正确的,有符号/无符号兼容性只适用于没有原型的调用,而不适用于varargs调用,更不用说特定的printf
了。 - Steve Jessopunsigned short x = 1; printf("%hu\n", x);
由于整数提升引入的无符号/有符号不匹配问题,也可能会出现未定义行为,尽管大多数人阅读它时可能不会预料到这种情况。 - dbush