3
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。有人可以解释为什么吗?多谢

4

6 回答 6

12

二进制

用二进制表示的 32 位数字 512 就是:

00000000000000000000001000000000

因为 2 的 9 次方是 512。通常,您从右到左读取位。

以下是其他一些二进制十进制数:

0001 = 1
0010 = 2
0011 = 3
0100 = 4

演员表:将 Int 重新解释为字节数组

当你这样做时:

int i = 512;
char *c = (char *)&i;

您可能知道,您将 4 字节整数解释为字符数组(8 位字节)。如果没有,这就是发生的事情:

&i

获取变量的地址i

(char *)&i

将其重新解释(或强制转换)为指向 char 类型的指针。这意味着它现在可以像数组一样使用。由于您知道 anint在您的机器上至少是 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十进制的,因为您已经用 00000001覆盖了第二个字节 00000010

请注意大端系统,字节将以与小端系统相反的顺序存储。这意味着如果你在其中一台机器上运行它,你会得到完全不同的结果。

于 2012-11-14T19:19:28.623 回答
2

记住 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。

于 2012-11-14T19:16:22.187 回答
2

在您想知道为什么您看到的是“奇怪”之前,请考虑您正在运行代码的平台以及其中的字节序

然后考虑以下

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;
}

在我的平台上(Macbook Air、OS X 10.8、Intel x64 Arch)

512 : 00020000
513 : 01020000
256 : 00010000

将您在上面看到的内容与您希望阅读的有关字节序的内容结合起来,您可以清楚地看到我的平台是小字节序。那你的呢?

于 2012-11-14T19:21:32.783 回答
1

由于您int通过指针对 a进行别名char,并且 achar是 8 位宽(一个字节),因此分配:

c[1] = 1;

将设置为的第二个i字节000000001。字节 1、3 和 4(如果sizeof(int) == 4)将保持不变。以前,第二个字节是000000010(因为我假设您使用的是基于 x86 的计算机,这是一种小端架构。)所以基本上,您将唯一设置为一个位置的位向右移动。那是除以2。

在 little-endian 机器和 32-bit 编译器上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 并且分配根本不会改变其他字节。

于 2012-11-14T19:18:22.620 回答
0

这取决于机器是这样little endian还是big endian数据如何存储在位中。有关更多信息,请阅读有关字节序的信息

C 语言不保证这一点。

512 in binary :

    =============================================
    0000 0000 | 0000 0000 | 0000 0010 | 0000 0000   ==>512
    =============================================
      12          34          56          78       

(0x12345678 假设这个 int 的地址)

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
    =============================================

同样对于 256 :因为您的 c 1将具有从右数第二个字节的地址。在下图中,

    =============================================
    0000 0000 | 0000 0000 | 0000 0001 | 0000 0000  ==>256
    =============================================

所以它在我们的系统中实现了数字的表示

于 2012-11-14T19:12:35.653 回答
0

这是因为您的机器是little endian,这意味着最低有效字节首先存储在内存中。

你说int i=512;5120x00000200十六进制的(为简单起见,假设是 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]c[0] =1;,记忆看起来像

  01 02 00 00

这意味着如果我们int再次将其视为小端(通过做printf("%d",i);),它是十六进制0x00000201,即513十进制。

现在,如果我们返回并更改c[1]c[1] =1;,您的记忆现在变为:

  00 01 00 00

现在我们回过头来把它解释为小端序int,它是十六进制0x00000100,也就是256十进制。

于 2012-11-14T19:26:08.830 回答