在下面的简单c测试程序中,两个printf语句返回不同的值。 (查看最后四个printf语句)。
int main ()
{
char c, *cc;
int i;
long l;
float f;
c = 'Z';
i = 15;
l = 7777;
f = 9999999312;
cc = &c;
printf("\nc = %c, cc= %u", *cc, cc);
cc = &i;
printf("\nc = %d, cc= %u", *cc, cc);
cc = &l;
printf("\nc = %ld, cc= %u", *( long* )cc, cc);
printf("\nc = %ld, cc= %u", *cc, cc);
cc = &f;
printf("\nc = %f, cc= %u", *(float *)cc, cc);
printf("\n cc= %u", cc);
printf("\nc = %f, cc= %u", *cc, cc);
printf("\nc = %f, cc= %u", *(float *)cc, cc);
printf("\nc = %f, cc using pointer = %p", *(float *)cc, cc);
printf("\nc = %f, cc using pointer =%p", *cc, cc);
return 0;
}
输出: -
c = Z, cc= 755585903
c = 15, cc= 755585904
c = 7777, cc= 755585912
c = 97, cc= 755585912
c = 9999998976.000000, cc= 755585908
cc= 755585908
c = 9999998976.000000, cc= 4294967288
c = 9999998976.000000, cc= 755585908
c = 9999998976.000000, cc using pointer = 0x7ffc37f4ace4
c = 9999998976.000000, cc using pointer =0xfffffff8
我在eclipse ide中运行它并使用Ubuntu Linux。
为什么表现不同?
答案 0 :(得分:3)
在某些地方,您使用了错误的格式说明符printf
。特别是,在这一行:
printf("\nc = %f, cc= %u", *cc, cc);
第一个参数的类型为char
,但您使用期望%f
的{{1}}。此外,第二个参数的类型为double
,但char *
期待%u
。使用错误的格式说明符会调用undefined behavior。
话虽如此,这是最有可能发生在幕后的事情:
在大多数托管实现中,浮点数不会像整数类型和指针那样被压入堆栈,而是存储在浮点寄存器中。
当您运行上述unsigned int
命令时,printf
和*cc
都被压入堆栈,因为它们都不是浮点数。当cc
然后查找它看到printf
的第一个参数时,它会从浮点寄存器中检索一个值。由于您确实传递了一个浮点值,因此您之前调用%f
时该值仍然存在,并且该值恰好是您实际想要打印的值,因此打印的内容就是<。 / p>
然后当printf
去打印下一个参数时,它会看到格式为printf
,以便从堆栈中提取值。该值为%u
,它指向*cc
表示中的第一个字节。
假设f
是IEEE754单精度浮点数,则其包含的值表示为float
。第一个字节是0xf8021550
。由于0xf8
指向cc
,在您的情况下似乎已签名,因此会将其解释为否定值。传递给char
时,该值会提升为printf
类型,因此传入的实际值为int
,这就是您看到要打印的内容。
但重申一下,您看到的输出是未定义的行为。如果在不同的机器上构建它,使用不同的编译器,或者只是使用不同的优化设置,输出可能会改变。
答案 1 :(得分:0)
以下提议的代码:
printf()
printf()
的所有格式字符串都缺少跟踪&#39; \ n&#39;。注意:建议的代码是在64位系统上使用以下命令行编译的:
gcc -ggdb -Wall -Wextra -Wconversion -std=gnu11 -pedantic -o "untitled2" "untitled2.c"
现在建议的代码:
#include <stdio.h>
int main ( void )
{
char c;
char *cc;
int i;
long l;
float f;
c = 'Z';
i = 15;
l = 7777;
f = 9999999312.0f;
cc = &c;
printf("\nc = %c, cc= %p", *cc, cc);
cc = (char*)&i;
printf("\nc = %d, cc= %p", *cc, cc);
cc = (char*)&l;
printf("\nc = %ld, cc= %p", *( long* )cc, cc);
printf("\nc = %ld, cc= %p", *(long*)cc, cc);
cc = (char*)&f;
printf("\nc = %f, cc= %p", *(float *)cc, cc);
printf("\n cc= %p", cc);
printf("\nc = %f, cc= %p", *(float*)cc, cc);
printf("\nc = %f, cc= %p", *(float*)cc, cc);
printf("\nc = %f, cc using pointer = %p", *(float *)cc, cc);
printf("\nc = %f, cc using pointer = %p", *(float*)cc, cc);
return 0;
}
结果输出为:
c = Z, cc= 0x7fffb663ae2f
c = 15, cc= 0x7fffb663ae30
c = 7777, cc= 0x7fffb663ae38
c = 7777, cc= 0x7fffb663ae38
c = 9999998976.000000, cc= 0x7fffb663ae34
cc= 0x7fffb663ae34
c = 9999998976.000000, cc= 0x7fffb663ae34
c = 9999998976.000000, cc= 0x7fffb663ae34
c = 9999998976.000000, cc using pointer = 0x7fffb663ae34
c = 9999998976.000000, cc using pointer = 0x7fffb663ae34