printf的意外输出
int a=5; float b=3.5; printf("%d",b); printf("\n%f",a);
任何人都可以告诉我为什么这段代码显示意外的输出(垃圾\ n3.5)
格式字符串不正确错误,根据您对a
和b
声明:
printf("%d",b); <-- "b is float" Wrong! printf("\n%f",a); <-- "a is an int" Wrong! -- Undefined behavior
应该:
printf("%f",b); printf("\n%d",a);
问: -为什么你得到那个输出?
这是由于代码的未定义行为:
来自国际标准©ISO / IEC ISO / IEC 9899:201x
7.16.1变量参数列表访问宏
(第270页)
7.16.1.1
va_arg
宏[...]如果没有实际的下一个参数,或者type与实际的下一个参数的类型不兼容(根据默认参数提升而提升),则
behavior is undefined
,除了以下情况:
- 一种类型是有signed integer type
,另一种类型是相应的unsigned integer
类型,并且该值可在两种类型中表示;
- 一种是指向void
的指针,另一种是指向字符类型的指针
您正在为%d
格式字符串传递一个float
,但printf
期望一个int
。
printf
是一个变量参数列表函数: printf(const char *format_string,...);
这意味着格式字符串之后的其余参数可以是任何类型和数字,并且编译器不知道它们应该是什么。 程序员可以提供printf
所期望的类型的参数。 printf
期望的内容由格式字符串决定。 当你在格式字符串中给出%d
时,printf函数将期望下一个参数是int
。 因为你正在传递一个float
,所以可能会发生一些奇怪的事情。 例如,构成浮点数的那些字节可能被视为int
,这不会给你任何有意义的值。
实际上它比那复杂一点。 有关如何将参数传递给变量参数函数的特殊规则。 其中一条规则是float
值传递为double
s。 这意味着您的float
值在传递给printf
之前首先转换为double
。 很可能你的平台上有一个double
是8个字节,而int
只有4个。 因此printf
函数可以将double
值的前四个字节视为int
。
更糟糕的是,在下一行中,正在传递一个int
,其中double
是预期的。 这意味着printf
函数可以将int
的前四个字节视为double
一部分,然后读取另外四个甚至不是参数的字节。
实际发生的细节是特定于平台的。 语言只是声明你不应该传递错误类型的参数,如果你这样做,就不会保证会发生。
因为a
变量是int类型,而你是为float类型指定格式字符串,反之亦然为变量b
。
注意 :
%d
用于整数类型
%f
是浮点型
你应该使用:
int a=5; float b=3.5; printf("%f",b); printf("\n%d",a);
int main() { int a=5; float b=3.5; printf("%f",b); //Use %f printf("\n%d",a); // Use %d }
参考: printf
printf
格式说明符错误导致大多数情况下未定义的行为。
但是,由于printf
是一个可变函数,并且可变参数函数的参数经过默认参数cast。 就像,char被转换为int。