关于机器相关指针值的混淆

时间:2013-10-12 20:05:53

标签: c++ c arrays pointers char

我正在对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 个答案:

答案 0 :(得分:2)

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

1 2

但是,在输出期间你试图引用与16/32位相同的数据,所以我们没有2个单字节,而是1个字,它存储在内存中为0x01 0x02,对于小端,它意味着我们应该交换它们,所以我们得到数字0x201,十进制表示法为513

对于big endian,它将是0x102,即十进制的258

答案 1 :(得分:2)

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 :(得分:1)

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

00000001 00000010 00000100 00001000

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

00001000 00000100 00000010 00000001

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

在您的示例中,512 in little endian是

00000000 00000010

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

00000010 00000000

,作为一个4字节的int,它是

00000000 00000000 00000010 00000000

(对于小端,这并不重要,因为额外的字节只是零)

将1写入第一个字节,将2写入第二个字节后,将获得4字节小端的内存

00000001 00000010 00000000 00000000

一个4字节的大端

00000001 00000010 00000010 00000000

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

和一个2字节的大端

00000001 00000010

解释2字节或4字节内存(2字节忽略的额外零)作为正常二进制数的小端数,它是

00000000000000000000001000000001 = 513

将4字节存储器解释为大端数,作为普通二进制数,它是

00000001000000100000001000000000 = 16908800

将2字节存储器解释为大端数字作为普通二进制数,它是

0000000100000010 = 258

我可能在计算中犯了一个错误,但希望你能得到这个想法。这就是在不同类型的指针之间进行转换时需要小心的原因。

答案 3 :(得分: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