这是否会调用未定义的行为?

时间:2011-05-01 21:26:58

标签: 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;
 }

printf("%d %d",a,b);行中,"%d"用于打印无符号类型。这会调用未定义的行为吗?为什么?

3 个答案:

答案 0 :(得分:5)

虽然明确允许您使用va_arg中的<stdarg.h>宏来检索作为unsigned int传递的参数(7.15.1.1/2) ),在同样适用于fprintf的{​​{1}}(7.19.6.1/9)的文档中,它明确指出如果任何参数不是格式说明符的正确类型 - 对于未修改的{{ 1}},即printf - 然后没有定义行为。

正如@bdonlan在评论中指出的那样,如果%d中的int(在这种情况下为某些b 2^N - 1)的值无法表示,那么未定义的行为在任何情况下都尝试使用Nint的身份访问该值。这仅适用于int的表示使用至少一个填充位的平台,其中相应的va_arg表示具有符号位。

即使在unsigned中可以表示int的值的情况下,我仍然将其视为技术上未定义的行为。作为实现的一部分,似乎允许实现使用内置魔术而不是(unsigned)-1来访问int的参数,并且如果您将某些内容作为va_args传递到哪里需要printf,否则您在技术上违反了unsigned的合同。

答案 1 :(得分:2)

在这一点上,标准并非100%明确。一方面,你得到va_arg的规范,其中说(§7.15.1.1/ 2):

  

如果没有实际的下一个参数,或者如果   type与实际的下一个参数的类型不兼容(如根据提升的那样)   对于默认参数提升),行为是未定义的,除了以下内容   例:

     
      
  • 一种类型是有符号整数类型,另一种类型是相应的无符号整数   类型,值可以在两种类型中表示;
  •   
  • 一种类型是指向void的指针,另一种是指向字符类型的指针。
  •   

另一方面,你得到printf(§7.19.6.1/ 9)的规范:

  

如果任何参数不是相应转换规范的正确类型,则行为未定义。“

鉴于printf将使用va_arg检索参数,我认为你可以用目标类型表示的值非常安全,但不是。由于您在传递-1之前已将-1转换为无符号,因此该值将超出可在signed int中表示的范围,因此行为将是未定义的。

答案 2 :(得分:1)

是的,if将始终评估为true,printf将尝试将unsigned打印为signed。由于signed类型可能具有陷阱表示,如果符号表示是一个补码,则可以是UB。