1

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

4 回答 4

5

表达式*p具有类型char。格式说明符%f需要类型为 的参数float。将错误类型的参数传递给可变参数函数,例如printf调用未定义的行为。

于 2012-08-20T01:41:05.477 回答
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*。

对于整数,您会看到

  • print p1 as an int ==> *p1是地址 50000004 处的字节,为 0,所以打印 0。
  • print b as an int ==> 显然b是 256,因为它是一个 int。
  • print p1 as an int ==> *p1是地址 50000004 处的字节,即 0,因此打印 0(如前所述)。

在小端机器上,您甚至可以尝试打印p1[1]为整数,您会看到 1(很有趣,嗯?请参阅http://ideone.com/daS6d)。

对于花车,情况有所不同。在许多处理器上,比如 x86-64,参数是在寄存器中传递的。你打printf了三遍。每次将要打印的东西都来自xmm0(假设 x86-64)。但是请注意,当您第一次尝试打印*pchar 时,没有传入任何内容xmm0*p被传入%edi),因此您在其中的任何垃圾都会被打印(可能是 0 或 0.0234892374 或其他)。但接下来你传入一个真正的浮点数xmm0并打印 3.14。但是当你来第三个 printf 时,你什么也没有传递(因为*p是一个字符),所以剩下的xmm0? 没错,3.14。也许它可能是别的东西,但很可能它没有改变。:)

于 2012-08-20T02:18:30.093 回答
0

它的行为不符合预期,因为 float* 和 char* 的大小不同。转换它们可能会牺牲您的表达准确性!

于 2012-08-20T01:45:17.190 回答
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 指出的那样,传递参数的实际方式可能会有所不同,因为这取决于实现。一些系统会将值传递到寄存器中,但要点保持不变。)

于 2012-08-20T02:07:39.443 回答