将float *转换为char *,int *和char *不会产生预期的结果

时间:2012-08-20 01:31:50

标签: c pointers casting

据我所知,输出应该是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

4 个答案:

答案 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打印为int ==> *p1是地址50000004处的字节,为0,因此打印0。
  • 将b打印为int ==>显然b是256,因为它是一个int。
  • 将p1打印为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)

简短的回答是,当您使用格式说明符charprintf类型传递给%f时,您正在调用未定义的行为,因此您不应该期望特别是。

长期答案取决于实现,但接下来是我对您平台上可能发生的事情的观察。当您要求printf打印double值(与%f格式说明符一样)时,它会从堆栈中读取下一个sizeof(double)字节并将其解释为浮点价值并打印出来。在第一次printf调用中,第一次生成新的堆栈帧时,堆栈上的数据在形成实际传递的char的位之后等于零浮点值。在第二次调用printf时,会生成一个新的堆栈帧,可能会覆盖第一次调用所执行的相同空间。在这种情况下,存在一个完整的double值,并按预期打印。当函数返回时,堆栈帧被“销毁”。作为效率问题,当函数返回并且内容保留时,堆栈帧通常不会被清零。在第三次调用printf时,您再次传递一个字节,而您要求printfsizeof(double)个字节解释为浮点值。从前一次调用到printf的堆栈帧现在包含从先前调用传递的double的值,其中一个字节用新参数中的字节覆盖,从而导致打印值。

如果我将您的第二个printf电话更改为:

printf("\nValue of a=%f", 1.234);

第三次调用printf打印(在我的系统上):

Value of *p=1.234000

似乎验证了上面给出的逻辑。

总之,您要求printf从堆栈中读取的数据多于实际传递给函数的数据,因此结果未定义。在您的情况下,读取的数据是先前调用的残余,这解释了您在特定平台上获得的结果。 (正如Ray指出的那样,参数传递的实际方式可能会有所不同,因为这取决于实现。有些系统会将值传递给寄存器,但该点保持不变。)