为什么%d在代码中显示* b和* c的两个不同值[b和c指向同一地址]

时间:2014-04-05 16:49:47

标签: c pointers

考虑下面的代码

{
float a=7.999,*b,*c;
b=&a;c=b;
printf("%d-b\n%d-c\n%d-a\n",*b,*c,a);
}

输出:

-536870912-b
1075838713-c
-536870912-a

我知道我们不允许使用%d而不是%f,但为什么* b和* c会给出两个不同的值? 两者都有相同的地址,有人可以解释一下吗? 我想知道它背后的逻辑

4 个答案:

答案 0 :(得分:4)

以下是您的考验的简化示例:

#include <stdio.h>
int main() {
  float a=7.999, b=7.999;
  printf("%d-a\n%d-b\n",a,b);
}

正在发生的事情是ab被转换为双精度(每个8个字节)以调用printf(因为它是可变的)。在printf函数内部,给定的数据(16字节)打印为两个4字节的整数。因此,您要将给定双数据之一的前半部分和后半部分打印为整数。

尝试更改printf对此的调用,您会看到两个双打的两半为整数:

  printf("%d-a1\n%d-a2\n%d-b1\n%d-b2\n",a,b);

我应该补充一点,就标准而言,这只是“未定义的行为”,因此上述解释(在gcc上测试)仅适用于某些实现。

答案 1 :(得分:2)

可能有很多原因。

最明显的 - 您的平台在整数寄存器中传递一些整数,在浮点寄存器中传递一些浮点数,导致printf查看从未设置为任何特定值的寄存器。

另一种可能性 - 变量大小不同。因此,printf正在查找未设置或被设置为其他操作的数据。

由于printf通过...获取其参数,因此类型协议对于确保函数的实现甚至在适当的位置查找其参数至关重要。

您必须深入了解您的平台和/或深入了解生成的汇编代码才能确定。

答案 2 :(得分:1)

使用错误的转换规范会调用未定义的行为。您可能会获得预期或意外的价值。您的程序可能会崩溃,可能会对不同的编译器或任何意外行为给出不同的结果

C11:7.21.6格式化输入/输出功能:

  

如果转换规范无效,则行为未定义.282)如果有任何参数   不是相应转换规范的正确类型,行为是   未定义。

答案 3 :(得分:0)

// Bad
float a=7.999,*b,*c;
b=&a;c=b;
printf("%d-b\n%d-c\n%d-a\n",*b,*c,a);

// Good
float a=7.999,*b,*c;
b=&a;c=b;
printf("%f-b\n%f-c\n%f-a\n",*b,*c,a);

使用指定为“%d”的整数格式而不是正确使用指定为“%f”的浮点数是az椭圆形无法解释为“未定义的行为”。

您需要使用正确的格式说明符。