#include <stdio.h>
int main(void)
{
int x = 1000;
char *ptr = &x;
printf("%d\n",*ptr);
return 0;
}
Output: -24
/*In gcc 4.4.3 in Ubuntu 10.04 OS*/
使用warning: initialization from incompatible pointer type
我认为如果指针的基本类型是int类型,那么它将从它指向的位置检索4个字节。然后O / P将是1000.但是当我将基类型更改为char然后当我取消引用它时,它将从它指向的位置检索1个字节。但答案是-24。 当我改变程序如下时
#include <stdio.h>
int main(void)
{
int x = 1000;
float *ptr = &x;
printf("%f\n",*ptr);
return 0;
}
输出变为0.000000并带有相同的警告。当我解除指针时,它将从它指向的位置检索4个字节。但是O / P是如何0.000000。我有点困惑。你们可以解释一下。我可以解释它。我C编程新手,所以在提出问题时有任何错误,请原谅我。感谢名单
答案 0 :(得分:3)
取消引用字符指针可以获得内部表示形式1000的第一个字符大小的块作为整数。然后将该字符提升为int
(根据varidac参数的规则),并解释为整数。
在你的机器上,使用该编译器,结果是-24。
字符大小的块可能是一个8位字节。
整数可能由4或8个字节表示。
内部表示可能是 2s-complement,并且可能以小端顺序存储。
您是否开始明白为什么结果不易预测?
使用浮点指针做同样的事情会返回一个float
大小的内存而不是char
,现在你可能有真正的(嘿!)麻烦,因为我们现在还不知道,如果float
表示甚至适合int
表示,那么您可能正在访问未初始化的内存。
在任何情况下,当您取消引用float*
时,它将该内存解释为float
(内部结构比字符或甚至2s补码整数更复杂),并将其提升到double
(再次对varidac参数的规则)然后尝试将该表示解释为整数(如果float
适合int
,double
可能不,因此您将double的 part 解释为int!)。啊。
这种情况甚至比上一次更糟糕,因为它涉及IEEE浮点表示标准,并且两次机会大小都不匹配。
所以这里的教训是:
辅助课程,仅适用于专家
因为如果你想要执行所有这些愚蠢的重新解释,你希望对它们进行精确而明确的控制。
答案 1 :(得分:1)
1000
为0x3E8
。 如果您的系统将int
存储为小端32位值,则x
会像这样存储在内存中:
+------+------+------+------+
| 0xE8 | 0x03 | 0x00 | 0x00 |
+------+------+------+------+
^
| ---increasing addresses--->
&x
对于第一种情况:
如果您的系统有一个8位char
,当您将&x
分配给char *ptr
然后取消引用它时,您会获得值{{1解释为0xE8
。
如果您的系统将char
类型视为已签名,如果已签名的表示形式为2的补码,则char
将被解释为{ {1}}。
对于第二种情况:
如果您的系统有一个小端32位0xE8
,当您将-24
分配给float
然后取消引用它时,您将获得该值将&x
的位模式解释为float *ptr
。
如果您的系统以IEEE 754格式表示0x000003E8
,则最高有效位表示符号(0表示它为正),接下来的8个最高有效位表示指数( 0表示数字为零或非规范化 - 非常小,其余23位表示“有效数”或“尾数”(0x3E8或1000)。这实际上具有值1000 * 2 -149 ,大约是1.4013 * 10 -42 - 您可以使用float
而不是{{{{}}来查看此值1 {} float
格式字符串。
答案 2 :(得分:-1)
您的问题的核心是您尝试将字符(*ptr
)打印为整数(%d
)。
因为您使用printf
将整数指定为%d
,所以将从堆栈中删除4个字节。
但是,因为您将char
传递给printf
,所以只传递了1个字节。 <{1}}检索的剩余3个字节将是随机堆栈数据,可以是任何内容。
结果,你得到-24或其他一些不一致的值。