据我所知,输出应该是3.14,3.14,3.14和256,256,256对吗?但这会产生不同的输出。谁能指导我完成这个并告诉我为什么会这样?
main()
{
float a = 3.14;
int b = 256;
char *p, *p1;
p = (char *) &a;
p1 = (char *) &b;
printf("\nFLOAT:");
printf("\nValue of *p=%f",*p);
printf("\nValue of a=%f",a);
printf("\nValue of *p=%f",*p);
printf("\n\nINTEGER:");
printf("\nValue of *p1=%d",*p1);
printf("\nValue of b=%d",b);
printf("\nValue of *p1=%d",*p1);
}
Output:
FLOAT:
Value of *p=0.000000
Value of a=3.140000
Value of *p=3.140001
INTEGER:
Value of *p1=0
Value of b=256
Value of *p1=0
答案 0 :(得分:5)
表达式*p
的类型为char
。格式说明符%f
需要类型为float
的参数。将错误类型的参数传递给类似printf
的可变函数会调用未定义的行为。
答案 1 :(得分:2)
我得到的答案略有不同(http://ideone.com/RG4uq),鉴于混合浮点和整数类型的可变函数的行为未定义,这并不令人惊讶。
这是发生了什么。假设内存从地址0x50000000,32位机器,小端
开始50000000 c3 f5 48 40 (a)
50000004 00 01 00 00 (b)
50000008 00 00 00 50 (p)
5000000c 04 00 00 50 (p1)
a的类型是float,b的类型是int,p的类型是char *,p1的类型是char *。
对于整数,你看
*p1
是地址50000004处的字节,为0,因此打印0。b
是256,因为它是一个int。*p1
是地址50000004处的字节,为0,因此打印0(如前所述)。在小端机器上,你甚至可以尝试打印p1[1]
作为整数,你会看到1(有趣,嗯?见http://ideone.com/daS6d)。
对于花车,情况有所不同。在许多处理器上,比如x86-64,参数在寄存器中传递。您正在呼叫printf
三次。每次打印的东西都来自xmm0
(假设是x86-64)。但是请注意,当您第一次尝试打印*p
这是一个字符时,在xmm0
中传递 (*p
已在%edi
中传递)你在那里得到的任何垃圾得到印刷(可能是0,或0.0234892374或其他)。但接下来你在xmm0
中传递一个真正的浮动并打印3.14。但是当你来到第三个printf时,再次没有传递任何东西(因为*p
是一个字符),那么xmm0
还剩下什么?那是对的3.14。它可能是其他东西,也许,但很可能它没有改变。 :)
答案 2 :(得分:0)
它的行为不符合预期,因为float *和char *的大小不同。转换它们可能会牺牲你的表达准确性!
答案 3 :(得分:0)
简短的回答是,当您使用格式说明符char
将printf
类型传递给%f
时,您正在调用未定义的行为,因此您不应该期望特别是。
长期答案取决于实现,但接下来是我对您平台上可能发生的事情的观察。当您要求printf
打印double
值(与%f
格式说明符一样)时,它会从堆栈中读取下一个sizeof(double)
字节并将其解释为浮点价值并打印出来。在第一次printf
调用中,第一次生成新的堆栈帧时,堆栈上的数据在形成实际传递的char
的位之后等于零浮点值。在第二次调用printf
时,会生成一个新的堆栈帧,可能会覆盖第一次调用所执行的相同空间。在这种情况下,存在一个完整的double
值,并按预期打印。当函数返回时,堆栈帧被“销毁”。作为效率问题,当函数返回并且内容保留时,堆栈帧通常不会被清零。在第三次调用printf
时,您再次传递一个字节,而您要求printf
将sizeof(double)
个字节解释为浮点值。从前一次调用到printf
的堆栈帧现在包含从先前调用传递的double
的值,其中一个字节用新参数中的字节覆盖,从而导致打印值。
如果我将您的第二个printf
电话更改为:
printf("\nValue of a=%f", 1.234);
第三次调用printf
打印(在我的系统上):
Value of *p=1.234000
似乎验证了上面给出的逻辑。
总之,您要求printf
从堆栈中读取的数据多于实际传递给函数的数据,因此结果未定义。在您的情况下,读取的数据是先前调用的残余,这解释了您在特定平台上获得的结果。 (正如Ray指出的那样,参数传递的实际方式可能会有所不同,因为这取决于实现。有些系统会将值传递给寄存器,但该点保持不变。)