输出C中该程序的解释?

时间:2012-06-06 06:38:15

标签: c endianness

我在C中有这个程序:

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

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

小端的输出为556。

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

问题是大端机器的答案是否仍然相同?

i = 300; => i = 100101100 //二进制中的word格式=> B B 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

相当于=> B B Hb 0010 00101100其中B = Byte且Hb =半字节

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

4 个答案:

答案 0 :(得分:8)

在小端32位系统中,int 3000x012c)通常(*)存储为4个连续字节,最低位:2C 01 00 00。当您递增以前为int指针&i的char指针时,您指向该序列的第二个字节,并将其设置为2会生成序列2C 02 00 00 - 当转回时到一个int,是0x22c或556。

(至于你对比特序列的理解......看起来有点偏.Endianness影响内存中的 byte 顺序,因为字节是最小的可寻址单元。字节内的位不要反转;低阶字节将是2C00101100),无论系统是小端还是大端。(即使系统确实反转了一个字节的位,它也是再次反转它们以将它们作为数字呈现给您,因此您不会注意到差异。)最大的区别在于该字节出现在序列中。 bit 顺序的唯一位置很重要,在硬件和驱动程序中,一次只能接收少于一个字节。)

在big-endian系统中,int通常(*)由字节序列00 00 01 2C表示(仅与字节顺序的小端表示不同 - 最高字节首先出现)。您仍在修改序列的第二个字节,但是......正在制作00 02 01 2C,其中int为0x02012c或131372。

(*)这里有很多东西发挥作用,包括两个补码(几乎所有系统都使用这些天......但C不需要它),价值sizeof(int),对齐/填充,以及系统是真正的大端还是小端还是半实现它。这是为什么要使用更大类型的字节来解决这个问题的一个重要原因,这往往会导致未定义或特定于实现的行为。

答案 1 :(得分:3)

这是您的int

int i = 300;     

这就是内存在&i中包含的内容:2c 01 00 00 在下一条指令中,您将i的地址指定为ptr,然后使用++ptr移至下一个字节,并将其值更改为2

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

现在内存中包含:2c 02 00 00(即556)。 区别在于i地址big-endian system中您会看到00 00 01 2C,并且在更改后00 02 01 2C

即使int的内部代表是实现定义的

  

对于有符号整数类型,对象表示的位应为   分为三组:值位,填充位和符号   位。不需要任何填充位;签名字母不得   任何填充位。应该只有一个符号位。每一点   值位应与对象中的相同位具有相同的值   相应的无符号类型的表示(如果有M   有符号类型中的值位和无符号类型中的N,则M≤N)。   如果符号位为零,则不应影响结果值。如果   符号位为1,该值应在其中一个中修改   以下方式: - 取消符号位0的相应值   (符号和幅度); - 符号位的值为 - (2M)(两个   补充); - 符号位的值为 - (2M - 1)('   补充)。其中哪些适用于实现定义,如   是符号位1的值和所有值位是否为零(对于   前两个),或带符号位和所有值位1(对于'   补码),是陷阱表示或正常值。在这种情况下   如果这个表示是,那么符号和幅度以及一个补码   一个正常值,它被称为负零。

答案 2 :(得分:3)

这是实现定义的。 int的内部表示根据标准是未知的,因此您所做的不是可移植的。见C标准第6.2.6.2节。

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

答案 3 :(得分:1)

我喜欢实验,这就是使用PowerPC G5的原因。

stacktest.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的答案已经完成,万一你怀疑这是实验证据。