6

我在 C 中有这个程序:

int main(int argc, char *argv[])
{

  int i=300;
  char *ptr = &i;
  *++ptr=2;
  printf("%d",i);
  return 0;
}

小端的输出是 556。

我试图理解输出。这是我的解释。

问题是答案在大端机器中是否保持不变?

我 = 300; => i = 100101100 //以二进制字格式 => BB Hb 0001 00101100 其中 B = 字节,Hb = 半字节

(A)=> 在内存中(假设它是小端))

0x12345678 - 1100 - 0010 ( Is this correct for little endian)

0x12345679 - 0001 - 0000

0x1234567a - 0000 - 0000

0x1234567b - 0000 - 0000

0x1234567c - 下一个 intezer 的位置(ptr++ 或 ptr + 1 的位置,其中 ptr 是一个 intezer 指针,因为 ptr 是 int 类型 => 在执行 ++ptr 时它将增加 4 个字节(int 的大小))

什么时候

(B)我们做 char *ptr = &i; ptr 将变为 char => 在执行 ++ptr 时它将增加 1 个字节(char 的大小),因此在执行 ++ptr 时它将跳转到位置 -> 0x12345679(具有 0001 - 0000)现在我们正在执行 + +ptr = 2 => 0x12345679 将被 2 覆盖 => 0x12345679 将具有 00 *10** - 0000 而不是 000* 1 * - 0000

所以新的内存内容将如下所示:

(C)

0x12345678 - 1100 - 0010

0x12345679 - 0010 - 0000

0x1234567a - 0000 - 0000

0x1234567b - 0000 - 0000

相当于 => BB Hb 0010 00101100 其中 B = 字节和 Hb = 半字节

我的推理是否正确?还有其他简短的方法吗?Rgds,软软的

4

4 回答 4

8

在 little-endian 32 位系统中,int 300( 0x012c) 通常 (*) 存储为 4 个连续字节,最低在前: 2C 01 00 00. 当您增加以前是 int 指针的 char 指针时&i,您将指向该序列的第二个字节,并将其设置为 2 使该序列2C 02 00 00- 当返回一个 int 时,它是0x22c或 556。

(至于您对位序列的理解......似乎有点偏离。字节序会影响内存中的字节顺序,因为字节是最小的可寻址单元。字节内的位不会反转;低位字节将是2C( 00101100) 系统是小端还是大端。(即使系统确实反转了一个字节的位,它也会再次反转它们以将它们作为数字呈现给您,因此您不会注意到区别。)最大的区别在于该字节出现在序列中的位置。顺序很重要的唯一地方是硬件和驱动程序,您一次只能接收不到一个字节。)

在 big-endian 系统中,int 通常 (*) 由字节序列表示00 00 01 2C(与 little-endian 表示仅在字节顺序上不同——最高字节在前)。不过,您仍在修改序列的第二个字节...making 00 02 01 2C,它作为 int 是0x02012c或 131372。

(*)很多事情都在这里发挥作用,包括二进制补码(现在几乎所有系统都使用它......但 C 不需要它)、 的值sizeof(int)、对齐/填充,以及系统是否真的很大-或little-endian或它的半成品实现。这就是为什么使用较大类型的字节经常导致未定义或特定于实现的行为的一个重要部分。

于 2012-06-06T06:50:42.103 回答
3

这是实现定义的。根据标准,int 的内部表示是未知的,因此您正在做的事情是不可移植的。请参阅 C 标准中的第 6.2.6.2 节。

但是,由于大多数实现使用带符号整数的二进制补码表示,因此字节顺序将影响结果,如 cHaos 回答中所述。

于 2012-06-06T06:56:32.850 回答
3

这是你的int

int i = 300;     

这就是内存中包含的内容&i2c 01 00 00 使用下一条指令,您将地址分配iptr,然后移动到下一个字节++ptr并将其值更改为2

char *ptr = &i;
*++ptr = 2;

所以现在内存包含:(2c 02 00 00即556)。不同之处在于,在大端系统i中,您会看到的地址00 00 01 2C,而在更改后:00 02 01 2C

即使 an 的内部表示int实现定义的

对于有符号整数类型,对象表示的位应分为三组:值位、填充位和符号位。不需要任何填充位;signed char 不应有任何填充位。应该有一个符号位。作为值位的每个位应与相应无符号类型的对象表示中的相同位具有相同的值(如果有符号类型中有 M 个值位,无符号类型中有 N 个值位,则 M ≤ N)。如果符号位为零,则不应影响结果值。如果符号位为 1,则应通过以下方式之一修改该值: — 符号位为 0 的对应值取反(符号和幅度);— 符号位的值为 -(2M)(二进制补码);— 符号位的值为 -(2M - 1)(反码)。implementation-defined,无论符号位为 1 且所有值位为零(对于前两个),还是符号位和所有值位为 1(对于一个补码)的值是陷阱表示还是正常值。在符号和幅度以及一个的补码的情况下,如果这个表示是一个正常值,它被称为负零。

于 2012-06-06T06:46:27.973 回答
1

我喜欢实验,这就是拥有 PowerPC G5 的原因。

堆栈测试.c:

int main(int argc, char *argv[])
{
  int i=300;
  char *ptr = &i;
  *++ptr=2;
  /* Added the Hex dump */
  printf("%d or %x\n",i, i);
  return 0;
}

构建命令:

powerpc-apple-darwin9-gcc-4.2.1 -o stacktest stacktest.c

输出:

131372 or 2012c

简历: cHao 的回答是完整的,如果您有疑问,这里是实验证据。

于 2012-06-06T19:25:10.160 回答