C代码指针拼图

时间:2013-04-07 06:38:22

标签: c pointers segmentation-fault 64-bit puzzle

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

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时出现分段错误。而我认为输出应该包括以下行而不是seg faulting:

B2 Info - 0xcfefb03d - A

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

3 个答案:

答案 0 :(得分:3)

  

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

可能的原因是,在您的平台上,指针是64位,而int是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);

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

答案 1 :(得分:1)

如果指针大小超过int的大小,那么

(int)&n可能会将n的地址截断为int,IOW中的位数(通常是这种情况)在64位CPU上,你会得到一个虚假的,截断的地址/指针,你不能安全地取消引用。

答案 2 :(得分:1)

在您的示例中,由于int为4个字节,因此在您投射&n并尝试将其分配给b2时会截断uintptr_t的值。要将指针值视为整数,请使用char * b2 = (((int) &n) + 1); ,这是一种无符号整数类型,无论平台容量如何,都可以安全地存储指针:

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

应该是:

{{1}}