int i=512;
char *c = (char *)&i;
c[0] =1;
printf("%d",i);
这个代码显示 "513",它将变量 i 加 1。
int i=512;
char *c = (char *)&i;
c[1] =1;
printf("%d",i);
这里显示的是256。将其除以2。
有人能解释一下为什么吗?非常感谢。
int i=512;
char *c = (char *)&i;
c[0] =1;
printf("%d",i);
这个代码显示 "513",它将变量 i 加 1。
int i=512;
char *c = (char *)&i;
c[1] =1;
printf("%d",i);
这里显示的是256。将其除以2。
有人能解释一下为什么吗?非常感谢。
用二进制表示的32位数512,就是:
00000000000000000000001000000000
因为2的9次方等于512。惯例上,你需要将二进制位从右至左依次读取。
以下是其他一些十进制数的二进制表示:
0001 = 1
0010 = 2
0011 = 3
0100 = 4
当您执行以下操作时:
int i = 512;
char *c = (char *)&i;
你正在将4字节整数解释为字符数组(8位字节),正如你可能已经知道的那样。如果不知道,这里是发生的事情:
&i
获取变量i
的地址。
(char *)&i
将其重新解释为指向字符类型的指针(或者强制转换),这意味着它现在可以像数组一样使用。由于您知道在您的计算机上,int
至少有32位,因此可以使用c[0],c[1],c[2],c[3]
访问它的字节。
根据系统的字节序不同,数字的字节可能会以大端(最高有效字节在前)或小端(最低有效字节在前)的方式排列。 x86处理器是小端。这基本上意味着数字512的排列方式如上例所示,即:
00000000 00000000 00000010 00000000
c[3] c[2] c[1] c[0]
我已将位组分成单独的8位块(字节),与它们在内存中的布局相对应。请注意,这里也是从右到左阅读它们,因此我们可以遵循二进制数字系统的惯例。
现在设置c[0] = 1
会产生以下影响:
00000000 00000000 00000010 00000001
c[3] c[2] c[1] c[0]
在十进制下等于 2^9 + 2^0 == 513
。
将 c[1] = 1
设置会产生以下效果:
00000000 00000000 00000001 00000000
c[3] c[2] c[1] c[0]
在十进制中,即为2 ^ 8 == 256
,因为您已经使用1覆盖了第二个字节的00000010。
请注意,在大端序系统上,字节的存储顺序与小端序系统相反。这意味着,如果您在其中一台机器上运行它,将会得到完全不同的结果。
code
(char *)&i code
如何被解释为4字节整数? - Rachit Kyte.Onei
的地址,然后将其强制转换为char指针。这意味着它可以被解释为字节数组。 - Daniel Hanrahan如果你觉得看到的内容很“奇怪”,请先考虑你运行代码的平台和其中的字节序(endianness)。
接下来请考虑以下内容:
int main(int argc, char *argv[])
{
int i=512;
printf("%d : ", i);
unsigned char *p = (unsigned char*)&i;
for (size_t j=0;j<sizeof(i);j++)
printf("%02X", p[j]);
printf("\n");
char *c = (char *)&i;
c[0] =1;
printf("%d : ", i);
for (size_t j=0;j<sizeof(i);j++)
printf("%02X", p[j]);
printf("\n");
i = 512;
c[1] =1;
printf("%d : ", i);
for (size_t j=0;j<sizeof(i);j++)
printf("%02X", p[j]);
printf("\n");
return 0;
}
512 : 00020000
513 : 01020000
256 : 00010000
结合您所看到的内容以及您希望阅读的字节序相关信息,您可以清楚地看到我的平台是小端字节序。那么你的呢?
请记住char是8位的,512的二进制表示为
512 = 10 0000 0000
当你执行char *c = (char *)&i;
时,你会得到:
c[1] = 10
c[0] = 0000 0000
当你执行c[0] = 1时,你会得到10 0000 0001
,它是513。
当你执行c[1] = 1时,你会得到01 0000 0000
,它是256。
由于您正在通过char
指针对int
进行别名处理,而char
宽度为8位(一个字节),因此赋值语句如下:
c[1] = 1;
将i
的第二个字节设置为000000001
。字节1、3和4(如果sizeof(int)==4
)将保持不变。以前,第二个字节是000000010
(因为我假设您使用的是基于x86的计算机,这是一种小端架构)。因此,您基本上将唯一设置的位向右移了一个位置。这是除以2。
在小端机器和带有32位int
的编译器上,最初在i
中有这四个字节:
c[0] c[1] c[2] c[3]
00000000 00000010 00000000 00000000
任务完成后,i
的值被设置为:
c[0] c[1] c[2] c[3]
00000000 00000001 00000000 00000000
因此它从512变成了256。
现在您应该明白为什么c [0] = 1
会导致结果为513 :-) 想想哪个字节被设置为1以及该赋值不会改变其他字节。
这取决于机器是 little endian
还是 big endian
,数据如何以位存储。要了解更多,请阅读关于 endianness 的内容。
C 语言对此没有保证。
512 in binary :
=============================================
0000 0000 | 0000 0000 | 0000 0010 | 0000 0000 ==>512
=============================================
12 34 56 78
(0x12345678 假设是这个整数的地址)
char *c =(char *)&i now c[0] either point to 0x78 or 0x12
Modifying the value using c[0] may result to 513 if it points to 0x78
=============================================
0000 0000 | 0000 0000 | 0000 0010 | 0000 0001 ==> 513
=============================================
or, can be
=============================================
0000 0001 | 0000 0000 | 0000 0010 | 0000 0000 ==>2^24+512
=============================================
=============================================
0000 0000 | 0000 0000 | 0000 0001 | 0000 0000 ==>256
=============================================
这是我们系统中数字表示的实现方式。
这是因为你的机器是小端,也就是最不重要的字节先存储在内存中。
你说过int i=512;
。 512
在十六进制中表示为0x00000200
(为简单起见,假设使用32位操作系统)。让我们看看i
在内存中以十六进制字节的形式存储:
00 02 00 00 // 4 bytes, least-significant byte first
char *c = (char *)&i;
将同一内存位置解释为字符数组 - 相同的内存,不同的解释:。 00 02 00 00
c[0][1][2][3]
现在我们用 c[0] = 1;
替换 c[0]
,内存看起来像这样
01 02 00 00
这意味着如果我们再次将其视为小端 int
(通过执行printf("%d",i);
),它的十六进制为0x00000201
,即十进制的513
。
现在,如果我们回去并使用c[1] = 1;
更改c[1]
,则您的内存现在变为:
00 01 00 00
int
,它的十六进制为0x00000100
,即十进制的256
。