2012-06-06 28 views
6

我用C有这样的程序:输出这个程序在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 //在字格式的二进制=> 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时它将跳转到位置 - > 0x12345679(它具有0001 - 0000) (p)将会变为类型char =>在执行++ ptr时它将增加1字节(char的大小) 现在我们正在做 ++ PTR = 2 => 0x12345679将由2 => 0x12345679将具有00 * 10 **被覆盖 - 0000而不是000 * * - 0000

所以新记忆的内容将是这样的:

(C)

0x12345678 - 1100 - 0010 

0x12345679 - 0010 - 0000 

0x1234567a - 0000 - 0000 

0x1234567b - 0000 - 0000 

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

是我的推理正确的吗?是否有此任何其它短方法? RGDS, 多愁善感

+2

[_void main_](http://users.aber.ac.uk/auj/voidmain.cgi)? – gliderkite

+4

我相信这种行为没有很好的定义,因为int的大小不能保证是4字节。 –

回答

8

在小端的32位系统中,INT 3000x012c)是典型地存储(*)作为4个连续字节,第一最低:2C 01 00 00。当你增加以前是int指针&i的字符指针时,你指向该序列的第二个字节,并将其设置为2将产生序列2C 02 00 00 - 当返回到int时,该序列为0x22c或556 。

(至于你的位序列的了解......这似乎有点过了。字节序影响字节顺序的记忆,字节是最小的可寻址单元。字节中的位没有得到反转;低位字节将是2C00101100)无论系统是小端还是大端(即使系统反转了一个字节的位,它会再次反转它们以将它们呈现给您一个数字,所以你不会注意到有什么不同)。最大的区别就是太大了e该字节出现在序列中。唯一的地方命令很重要,是在硬件和驱动程序等您可以接收少于一个字节在一次)。

在大端系统中,int通常由(*)表示字节序列00 00 01 2C(与字节顺序中的小端表示不同 - 最高字节先出现)。你还在修改序列的第二个字节,但...做00 02 01 2C,它作为一个int 0x02012c或131372.

(*)许多事情都在这里发挥作用,包括补(几乎所有的系统都使用这些日子......但C不需要它),sizeof(int)的值,对齐/填充以及系统是真正的大或小端还是半端实现。这是为什么使用更大类型的字节时经常会导致未定义或特定于实现的行为的一个重要组成部分。

+0

“当你增加以前是int指针'&i'的字符指针时,你指向该序列的第二个字节[。]”如果你不小心,指针算术真的是一件棘手的小事情。 – JAB

3

这是您的int

int i = 300;  

而这正是存储器包含在&i2c 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的内部rappresentation是实现定义

对于有符号的整数类型,所述对象表示的比特必须 可以分为三组:值的比特,填充比特,和标志 位。不需要任何填充位;有符号的字符不应该有任何填充位 。应该只有一个符号位。 是一个值位的每个位的值应与对应的无符号类型的对象 中的同一位具有相同的值(如果有符号类型中有值位,并且无符号类型中有N,则M≤N )。 如果符号位为零,则不会影响结果值。如果 的符号位是1,则应该按照以下方式在 之一中修改该值: - 符号位0的相应值被取消 (符号和量值); - 符号位的值 - (2M)(2的 补码); - 符号位的值为 - (2M - 1)(其中' 补码)。这些适用的是实现定义的,因为 是符号位1和所有值位为零(前两个为 ),还是符号位和所有值位1(用于' 互补)的值)是陷阱表示还是正常值。在符号和幅度以及1的补码 的情况下,如果该表示是 是正常值,则称其为负零。

+0

问题是大endian会发生什么。 –

3

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

但是,由于大多数实现使用signed int的二进制补码表示,所以endianness会影响cHaos答案中所述的结果。

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 

简历:王超的答案是完整的,如果你还有疑问在这里是实验证据。