【问题标题】:Confusion about machine-dependent pointer values关于机器相关指针值的混淆
【发布时间】:2013-10-12 20:05:53
【问题描述】:

我正在对 C 中的指针进行一些审查,但我对遇到的一些代码感到有些困惑。我在qeeksquiz.com/pointers 上做一个测验来复习,我遇到了这段代码:

#include<stdio.h> 
int main() 
{ 
   int a; 
   char *x; 
   x = (char *) &a; 
   a = 512; 
   x[0] = 1; 
   x[1] = 2; 
   printf("%d\n",a);   
   return 0; 
}

当我遇到x = (char *) &amp;a 时,我有点困惑。我知道 x 是一个包含 a 地址的指针,但是当我们分配 x[0] = 1x[1] = 2; 时,打印出来的答案是 513。答案谈到它如何取决于我们使用的机器以及如何使用little-endian 机器改变了它读取二进制文件的方式。我对我们如何从 512 到 513 感到非常困惑。我猜这是因为 x[0] = 1 但我不是 100% 确定。有人可以帮忙解释一下吗?如果我们分配x[0] = 2,那么改变的价值是什么?

感谢您的帮助!

【问题讨论】:

  • int 存储为字节序列。这里只初始化了 2 个字节:然后 value 计算为 x[0]+ 256*x[1] = 1 + 256*2 = 513。如果它是一个不同字节序的机器,那么(假设 int 使用了 2 个字节,这并不总是正确的)它会反过来:x[1] + 256*x[0] = 2 + 256 = 258。
  • 将 x[1] 乘以 256 是从哪里得到的?
  • 256 是 2**8,8 是一个字节的位数。
  • @user1871869: 256 来自基地。正如 base-10 数字 12 表示 1 * 10 + 2 * 1,base-16 数字 0x12 表示 1 * 16 + 2 * 1,base-256 数字 (1, 2) 表示 1 * 256 + 2 * 1

标签: c++ c arrays pointers char


【解决方案1】:

ASCII 艺术!

                   Little endian              Big endian

               +----+----+----+----+     +----+----+----+----+
a = 0x200:     | 00 | 02 | 00 | 00 |     | 00 | 00 | 02 | 00 |
               +----+----+----+----+     +----+----+----+----+

               +----+----+----+----+     +----+----+----+----+
x[0] = 1:      | 01 | 02 | 00 | 00 |     | 01 | 00 | 02 | 00 |
               +----+----+----+----+     +----+----+----+----+

               +----+----+----+----+     +----+----+----+----+
x[1] = 2:      | 01 | 02 | 00 | 00 |     | 01 | 02 | 02 | 00 |
               +----+----+----+----+     +----+----+----+----+

result:          1x1 + 2x256 = 513     1x16777216 + 1x65536 + 2x256 + 0x1 = big

【讨论】:

    【解决方案2】:

    因为 x 是指向 char 的指针,这意味着 x[0] 和 x[1] 是对单字节数据的引用,所以在你的内存中你有这样的数据:

    1 2
    

    但是,在输出过程中,您试图引用与 16/32 位相同的数据,所以我们没有 2 个单字节,而是 1 个字,它以 0x01 0x02 的形式存储在内存中,对于 little endian,这意味着我们应该交换他们,所以我们得到数字 0x201,即十进制的 513

    对于大端,它将是 0x102,即十进制的 258

    【讨论】:

    • 不依赖sizeof(int)吗?
    • 只有 16 位 int 才为 258。对于 32 位 int,它将是 0x01020000
    【解决方案3】:

    整数由字节序列组成。但是不同系统中字节的顺序是不同的。例如,考虑数字 134480385(二进制 = 00001000000001000000001000000001)。在小端系统上,它是(在左边的最低地址)

    00000001 00000010 00000100 00001000

    但在大端系统上,字节存储方式相反。 LEFT 仍然是最低的地址。

    00001000 00000100 00000010 00000001

    当您将整数 a 的地址转换为 char(字节)指针时,它指向整数中的第一个字节(最低地址)。向指针写入 1 时,最低字节设置为 00000001。但是 char 只有 1 个字节长,所以其他字节不变。然后第二个字节设置为00000010。

    在您的示例中,小端序中的 512 是

    00000000 00000010

    Big endian 比较棘手,因为结果取决于 int 中有多少字节。它通常是 4,但也可能是 2 或更多。作为 2 字节 int,内存中的 512 是

    00000010 00000000

    作为一个 4 字节的 int 是

    00000000 00000000 00000010 00000000

    (对于小端没有关系,因为额外的字节只是零)

    将 1 写入第一个字节,将 2 写入第二个字节后,您将在内存中获得一个 4 字节的 little endian

    00000001 00000010 00000000 00000000

    4 字节大端序

    00000001 00000010 00000010 00000000

    请注意,第三个字节中的位仍然存在。这是因为我们只写入了前两个字节。第三个和第四个字节不变。

    和一个 2 字节的大端序

    00000001 00000010

    将 2 字节或 4 字节内存(2 字节忽略多余的零)解释为小端数作为正常二进制数

    00000000000000000000001000000001 = 513

    将 4 字节内存解释为大端数作为普通二进制数

    00000001000000100000001000000000 = 16908800

    将 2 字节内存解释为大端数作为普通二进制数

    0000000100000010 = 258

    我的计算可能有误,但希望你能明白。这就是为什么在不同类型的指针之间进行转换时需要小心的原因。

    【讨论】:

      【解决方案4】:

      正如其他人所指出的,诀窍是了解整数和字符在内存中的表示方式。我编写了一些 C++ 代码,试图准确地向您展示这一点。将其粘贴到文件中,编译并运行;然后更改main 中的值,看看会发生什么。代码如下:

      #include <stdio.h>
      
      // print one byte as a binary number
      void print_binary(unsigned u) {
          for (int i = 7; i >= 0; --i)
              printf("%d", (u >> i) & 1);
      }
      
      // print a number's binary representation
      template <typename T>
      void print_int_binary(T i) {
          char *cp = (char*)&i;
          for (int i = 0; i < sizeof(T); ++i) {
              print_binary(cp[i]);
              printf(" ");
          }
          printf("\n");
      }
      
      // show how the variable is represented in memory
      template <typename T>
      void print_var_binary(const char *name, T t) {
          printf("%s is stored as %d bytes:\n", name, (int)sizeof(t));
          print_int_binary(t);
      }
      
      #define PRINT(a) print_var_binary(#a, a);
      
      int main() {
          PRINT((int)513)
          PRINT((char)2)
      }
      

      当我在我的(小端)计算机上运行它时,它会打印:

      (int)513 is stored as 4 bytes:
      00000001 00000010 00000000 00000000 
      (char)2 is stored as 1 bytes:
      00000010 
      

      【讨论】:

        猜你喜欢
        • 2020-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-25
        相关资源
        最近更新 更多