C 这会调用未定义的行为吗?
考虑以下C程序:C 这会调用未定义的行为吗?,c,undefined-behavior,C,Undefined Behavior,考虑以下C程序: #include <stdio.h> int main(){ int a =-1; unsigned b=-1; if(a==b) printf("%d %d",a,b); else printf("Unequal"); return 0; } #包括 int main(){ int a=-1; 无符号b=-1; 如果(a==b) printf(“%d%d”,a,b); 其他的 printf
#include <stdio.h>
int main(){
int a =-1;
unsigned b=-1;
if(a==b)
printf("%d %d",a,b);
else
printf("Unequal");
return 0;
}
#包括
int main(){
int a=-1;
无符号b=-1;
如果(a==b)
printf(“%d%d”,a,b);
其他的
printf(“不平等”);
返回0;
}
在printf的
行中(“%d%d”,a,b)代码>,“%d”
用于打印无符号类型。这是否会调用未定义的行为及其原因?尽管在fprintf
(7.19.6.1/9)的文档中,明确允许您使用中的va_arg
宏来检索作为无符号作为int
(7.15.1.1/2)传递的参数,该参数也适用于printf
,它明确指出,如果任何参数不是格式说明符的正确类型(对于未修改的%d
,即int
),则不会定义该行为
正如@bdonlan在一篇评论中所指出的,如果b
(在本例中,对于某些N
,对于2^N-1
)的值在int
中不可表示,那么在任何情况下,尝试使用va_arg
以int
的形式访问该值都是未定义的行为。这仅适用于无符号
表示至少使用一个填充位的平台,而相应的int
表示具有符号位
即使在(unsigned)-1的值可以用int
表示的情况下,我仍然认为这是技术上未定义的行为。作为实施的一部分,似乎允许实现使用内置魔术而不是va_args
来访问printf
的参数,如果您将某个内容作为未签名的传递,其中需要int
,则您在技术上违反了printf
的合同,if
将始终计算为true,而printf
将尝试将未签名的
打印为已签名的
。由于有符号
类型可能有陷阱表示,如果符号表示是一个人的补码,则可能是UB 在这一点上,标准不是100%清楚。一方面,您得到了va_arg
的规范,其中说明(§7.15.1.1/2):
如果没有实际的下一个参数,或者
类型与实际下一个参数的类型不兼容(根据
对于默认参数,该行为未定义,但以下情况除外
案例:
- 一种类型是有符号整数类型,另一种类型是相应的无符号整数
类型,并且值在这两种类型中都可以表示李>
- 一种类型是指向void的指针,另一种类型是指向字符类型的指针
另一方面,您得到了printf
(§7.19.6.1/9)的规范:
如果任何参数不是相应转换规范的正确类型,则行为未定义。“
考虑到printf
将检索带有va_arg
的参数,我想说的是,使用可以在目标类型中表示的值是非常安全的,但不是其他类型。由于在传递它之前已将-1转换为无符号,因此该值将超出可以在有符号I中表示的范围nt,因此行为将是未定义的。7.15.1.1/2中的异常如下:“如果类型与实际下一个参数的类型不兼容[…],则行为是未定义的,除非[其中]一种类型是有符号整数类型,另一种类型是相应的无符号整数类型,并且值在两种类型中都可表示。”(强调矿山).由于-1
在这两种类型中都不可表示,因此即使没有7.19.6.1,行为也未定义/9@bdonlan:从技术上讲,b
没有值-1
,对于某些N
,它有值2^N-1
。此值是否在int
和未签名的
中都可以表示,取决于rm依赖-通常不是,我同意你。如果一个行为只有在某个实现定义的因子为真时才是未定义的,那么它实际上是未定义的,因为一致性实现可以自由选择INT_MAX和UINT_MAX的值,这将允许它在有问题的printf调用时召唤鼻魔。@bdonlan:它不是“有效未定义的”“因为实现必须记录INT_MAX
和UINT_MAX`,所以可以确定它是否不是特定实现的UB。除非您的意思是“实际上未定义”?它在任何情况下都不是通用的可移植的。我的意思是,一个程序通常不能为它假设任何特定的语义。当然,如果INT_MAX>=(UINT_MAX-1)
,你可以做一个,但是,在实践中,你最好假设它总是UB,并且用iteexcept(unsigned)-1变成(UINT_MAX-1),这通常超出了INT_MAX的范围…我想知道是否有任何实现使用%X
和带符号值的friends除了显示基础位的十六进制表示之外还能做什么?如果没有,这似乎是标准中应该提供的有用行为,特别是因为现有代码的性能依赖于该行为。