【问题标题】:No idea what this pointer could be pointing to and unable to interpret the result不知道这个指针可能指向什么并且无法解释结果
【发布时间】:2017-03-21 19:59:47
【问题描述】:

这是在考试中作为过去的问题给出的,但我无法理解最后 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

【问题讨论】:

  • 提示:写下999 的二进制表示,考虑到unsigned int 变量很可能占用4 个字节。
  • 将那些 %d 更改为 %x 并再次运行它。它应该更加清晰。
  • @SingerOfTheFall 最重要的部分是most likely,它取决于架构,那么这个问题无法正确回答
  • 999 = 231 * 2^0 + 3 * 2^8 + 0 * 2^16 + 0 * 2^24
  • 此发布的代码无法编译。分析表明它缺少两个语句:#include <stdio.h>#include <stdlib.h> 编译器还输出有关未使用变量argcargv[] 的警告当不使用这些参数时,使用签名int main( void )。当问一个运行时问题(因为这个问题)时,请发布 1)干净编译的代码,2)实际输入,如果有的话 3)实际输出和 4)预期输出。

标签: c++ c pointers hex


【解决方案1】:

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

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

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

在 x86 这样的小端机器中,您的 unsigned int999 表示为:

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

| 之间的数字是 byte 中的值。因此,它将被打印为:

231 3 0 0

在另一台机器上,假设是 32 位的 Big Endian(例如 Atmel 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

【讨论】:

    【解决方案2】:

    此代码取决于平台。

    鉴于您的平台是:

    • 小端序
    • CHAR_BIT == 8
    • sizeof(int) == 4

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

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


    作为旁注,您应该提请您在学校/学院/大学的讲师注意,由于此代码依赖于平台,因此作为考试的一部分给出的示例非常糟糕。

    【讨论】:

      【解决方案3】:

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

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

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

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

      在小端系统中,随后是英特尔处理器和当今大多数微控制器,首先存储最低有效字节,最后存储最高有效字节。

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

      【讨论】:

        【解决方案4】:

        nines 是堆栈上的一个无符号 32 位整数(请注意,int 可能是 64 位宽,但这里似乎并非如此)。 ptr 是一个指针,它被初始化为nines 的地址。由于它是一个指针,因此您可以使用数组语法来访问指向地址处的值。我们假设它是一个小端机器,所以ptr[0]nines 的第一个(最低有效)字节,ptr[1] 是下一个字节,等等。 231 是最低有效字节的值,十六进制为0xe7

        【讨论】:

          【解决方案5】:

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

          nines 的值是十进制的 999,十六进制的 3E7,根据打印的值,它以 little-endian 字节顺序存储(“最低有效”字节在前)。

          如果您也将值转换为十六进制,则更容易查看:

          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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-09-09
            • 2023-03-21
            • 1970-01-01
            • 1970-01-01
            • 2010-12-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多