不知道这个指针可能指向什么,也无法解释结果

问题描述:

这是考试中的过去问题,但我无法理解最后4个printf函数的结果。我得到的转换为十六进制为第2,但我实在不明白怎么会有在不知道这个指针可能指向什么,也无法解释结果

ptr[0] to ptr[3] 

是字符这是被编译并运行的代码段。

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

    typedef unsigned char byte; 

    unsigned int nines = 999; 
    byte * ptr = (byte *) &nines; 

    printf ("%x\n",nines); 
    printf ("%x\n",nines * 0x10); 
    printf ("%d\n",ptr[0]); 
    printf ("%d\n",ptr[1]); 
    printf ("%d\n",ptr[2]); 
    printf ("%d\n",ptr[3]); 

    return EXIT_SUCCESS; 
} 

,这是相应的输出

3e7 
3e70 
231 
3 
0 
0 
+3

提示:考虑到'unsigned int'变量最可能需要4个字节,写下'999'的二进制表示形式。 – SingerOfTheFall

+4

将这些'%d'更改为'%x'并再次运行。它应该更清楚。 – WhozCraig

+0

@SingerOfTheFall最重要的部分是'最有可能的',它取决于体系结构,那么这个问题就不能正确地回答。 – Danh

这个代码显示的每个单独字节的值(假定为32位)的数nines

nines的值是十进制999,3E7以十六进制,并根据印刷的值,它的存储在小端字节顺序(‘最小显著’字节至上)。

它很容易看到,如果你值转换为十六进制还有:

printf ("%x\n",ptr[0]); 
printf ("%x\n",ptr[1]); 
printf ("%x\n",ptr[2]); 
printf ("%x\n",ptr[3]); 

这将显示此:

E7 
3 
0 
0 

此外,你可以这样理解十进制值:

231 + 3*256 + 0*65536 + 0*16777216 = 999 

nines是栈上的一个无符号的32位整数(注意这是可能的对于int是64位宽,但在这里似乎不是这种情况)。 ptr是一个指针,它被初始化为地址nines。由于它是一个指针,因此可以使用数组语法来访问指向地址的值。我们假设它是一个小端机器,所以ptr[0]nines第一(最低显著)字节,ptr[1]是下等 231是那么至少显著字节的值,以十六进制是0xe7

当您执行byte * ptr = (byte *) &nines;时,您将ptr的地址设置为与nines相同的地址。这有999值和十六进制是0x3e7

从这个问题,我假设的int有4个字节,这是一个小端系统。即像这样存储字节。

--------------------------------- 
| 0xe7 | 0x03 | 0x00 | 0x00 | 
--------------------------------- 
    ptr  ptr+1 ptr+2 ptr+3 

所以,当你打印出来,你得到的231300值(231等于0xe7)

在小尾数系统,其次是英特尔处理器和大多数微控制器今天,最低有效字节首先被存储并且最高有效字节最后被存储。

另一方面,我们有大端系统,其次是一些较老的摩托罗拉控制器和电源电脑。在此,最重要的字节首先被存储。这些系统中的输出将是0,0,3和231。

如果你有这样的考试,我建议你尽快更换讲师。

unsigned int的表示是指定的实现,它取决于你的机器的大小,字节顺序。

无论如何,铸造从unsigned int*char*然后直接读取它的值应该是一个未定义的行为。

在像x86机器小端,你的999unsigned int表示为:

| 0xE7 | 0x03 | 0x00 | 0x00 | 
----------------------------- 
    ptr ptr+1 ptr+2 ptr+3 

|之间的数量是在byte值。因此,将被打印为:

231 3 0 0 

在另一台机器,比方说,一个32位,大端(例如爱特梅尔AVR32),它将被表示为:

| 0x00 | 0x00 | 0x03 | 0xE7 | 
----------------------------- 
    ptr ptr+1 ptr+2 ptr+3 

然后它将打印:

0 0 3 231 

在另一台机器上,比方说,一个32位,中端,这将表示为:

| 0x03 | 0xE7 | 0x00 | 0xE0 | 
----------------------------- 
    ptr ptr+1 ptr+2 ptr+3 

那么它会打印:

3 231 0 0 

在较老的机器,比方说,一个16位的小端机,它被表示为:

| 0xE7 | 0x03 | xx| xx | 
------------------------ 
    ptr ptr+1 ptr+2 ptr+3 

xx是不确定的值,另外还有一个未定义的行为。

在64位大端机器,它被表示为:

| 0x00| 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x03 | 0xE7 
----------------------------- 
    ptr ptr+1 ptr+2 ptr+3 

它将打印:

0 0 0 0 

这是说,有一个为考试的问题没有确切的答案。如果是的话,它仍然会调用未定义的行为。

进一步阅读有关Endiannessundefined behavior

该代码是依赖于平台的。

鉴于你的平台是:

  • 的Little Endian
  • CHAR_BIT == 8
  • sizeof(int) == 4

999内存中的二进制表示11100111 00000011 00000000 00000000

因此,999在内存中的十进制表示形式为231 3 0 0


作为一个侧面说明,你应该把它带到你的老师在学校/学院/大学的注意,既然这个代码是依赖于平台的,它被赋予作为一项非常坏的榜样的考试。