2

我正在查看一个同学发布的一些代码,为了这个例子,它已经被简化了:

int main()
{
    int n = 0x4142;
    char * a = (char *) &n;

    char * b1 = (((char *) &n) + 1);
    char * b2 = (((int) &n) + 1);

    printf("B1 Points to 0x%x - B2 Points to 0x%x\n", b1, b2);

    printf("A Info - 0x%x - %c\n", a, *a);
    printf("B1 Info - 0x%x - %c\n", b1, *b1);
    printf("B2 Info - 0x%x - %c\n", b2, *b2);

   return 0;
}

输出是:

B1 Points to 0xcfefb03d - B2 Points to 0xcfefb03d
A Info - 0xcfefb03c - B
B1 Info - 0xcfefb03d - A
Segmentation fault (core dumped)

尝试打印 b2 时出现分段错误。而我认为输出应该包括以下行而不是段错误:

B2 Info - 0xcfefb03d - A

为什么会这样?b1 和 b2 都是 char*,它们都指向同一个地址。这是在 64 位机器上,其中 sizeof(char*) == 8 和 sizeof(int) == 4 如果重要的话。

4

3 回答 3

3

但它在 64 位计算机上出现段错误

可能的原因是,在您的平台上,指针是 64 位的,而整数是 32 位的。因此,当您将指针投射到 时int,您会丢失信息。

我的编译器对此特别警告:

test.c:7:19: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]

使用以下程序很容易看到这一点:

#include <stdio.h>

int main()
{
   char *s = "";
   printf("%p %p\n", s, (char*)(int)s);
   return 0;
}

在我的电脑上,这会打印两个不同的地址(第二个地址的最高位被切掉)。

我不太明白的是b1和b2都是char *,它们都指向同一个地址

实际上,它们并不指向同一个地址。您的printf()格式说明符都是错误的。第一个printf()应该是:

printf("B1 Points to %p - B2 Points to %p\n", b1, b2);

当你运行它时,你会看到地址不同。

于 2013-04-07T06:43:51.720 回答
1

(int)&n如果指针大小比 int 的大小长(这在 64 位 CPU 上通常是这种情况),则可能会将地址截断n到 IOW 中有多少位,您会得到一个虚假的截断地址/指针int不能安全地取消引用。

于 2013-04-07T06:45:19.140 回答
1

在您的示例中,由于 anint是 4 个字节,因此&n当您转换它并尝试将其分配给b2. 要将指针值视为整数,请使用uintptr_t无符号整数类型,无论平台容量如何,都可以安全地存储指针:

char * b2 = (((int) &n) + 1);

应该:

char * b2 = ((uintptr_t) &n) + 1;
于 2013-04-07T06:47:47.533 回答