0

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

谢谢您的帮助!

4

4 回答 4

3

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
于 2013-10-12T20:32:42.183 回答
2

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

1 2

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

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

于 2013-10-12T20:11:56.863 回答
1

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

00000001 00000010 00000100 00001000

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

00001000 00000100 00000010 00000001

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

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

00000000 00000010

大端比较棘手,因为结果取决于 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

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

于 2013-10-12T20:33:44.353 回答
0

正如其他人指出的那样,诀窍是了解整数和字符在内存中的表示方式。我编写了一些 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 
于 2013-10-12T21:11:05.573 回答