我有以下代码:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int n = 260;
int *p = &n;
char *pp = (char*)p;
*pp = 0;
printf("n = %d\n", n);
system("PAUSE");
return 0;
}
该程序的输出放置为n = 256
。
我可能理解为什么,但我不确定。
请问有人能给我一个明确的解释吗?
非常感谢。
答案 0 :(得分:11)
int
260(= 256 * 1 + 4)在内存中看起来像这样 - 请注意,这取决于机器的endianness - 这也适用于32位( 4字节)int
:
0x04 0x01 0x00 0x00
通过使用char
指针,指向第一个字节并将其更改为0x00
,这会将int更改为256(= 256 * 1 + 0)。
答案 1 :(得分:3)
你显然是在使用小端机器。发生的事情是你从一个占用至少两个字节的int开始。值260是256 + 4。 256进入第二个字节,第4个进入第一个字节。当你向第一个字节写0时,你只剩下第二个字节中的256个。
答案 2 :(得分:1)
我明白改变价值究竟发生了什么:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int n = 260;
int *p = &n;
char *pp = (char*)p;
*pp = 20;
printf("pp = %d\n", (int)*pp);
printf("n = %d\n", (int)n);
system("PAUSE");
return 0;
}
输出值是 20 和 276
所以基本上问题不在于你有数据丢失,是char指针只指向int的第一个字节,所以它只改变了,其他字节没有改变,这就是为什么那些奇怪的值(如果你在INTEL处理器上,第一个字节是最不重要的,这就是你改变数字“最小”部分的原因
答案 3 :(得分:1)
在C中,指针根据与指针关联的类型引用字节块。因此,在您的情况下,整数指针指的是大小为4个字节的块,而char只有一个字节长。当您将char设置为0时,它只会更改整数值的第一个字节,但由于数字在现代机器的内存中的存储方式(实际上与编写它的方式相反),您将覆盖最低有效字节(这是4)你剩下w / 256作为值
答案 4 :(得分:0)
你的问题是作业 * pp = 0; 您正在取消引用指向n的pp,并更改n。 但是,pp是一个char指针,所以它不会改变所有n 这是一个int。这导致其他答案中的二元并发症。
答案 5 :(得分:0)
就C语言而言,您正在做的描述是修改int
变量n
的表示。在C中,所有类型都有一个“表示”作为一个或多个字节(unsigned char
),通过转换指向char *
或unsigned char *
的指针来访问底层表示是合法的 - 后者如果我在这里进入这些原因会更加不必要地使事情复杂化,这样做会更好。
正如schnaader回答的那样,在一个小端上,二十三补充了32位int
的实现,260的表示是:
0x04 0x01 0x00 0x00
并用0
覆盖第一个字节,产生:
0x00 0x01 0x00 0x00
是这种实现的256的表示。
C允许具有填充位和陷阱表示的实现(如果访问它们会引发信号/中止您的程序),因此通常以这种方式覆盖部分但不是全部int
是不安全的去做。尽管如此,它确实可以在大多数真实世界的机器上运行,如果您使用类型uint32_t
,它将保证可以工作(尽管这些位的排序仍然依赖于实现)。
答案 6 :(得分:0)
考虑32位系统,
256
将以这样的方式表示。
00000000 (Byte-3) 00000000 (Byte-2) 00000001(Byte-1) 00000100(Byte-0)
现在,当p
被类型转换为char指针时,指针上的标签会发生变化,但内存内容不会变化。这意味着较早的p
可以访问4个字节,因为它是一个整数指针,但现在它只能访问1个字节,因为它是一个char指针。因此,只有LSB变为零,而不是所有4个字节。
它变成了
00000000 (Byte-3) 00000000 (Byte-2) 00000001(Byte-1) 00000000(Byte-0)
因此,o / p为256
。