C编译器重定位与另一个变量重叠的指针

时间:2013-04-05 18:59:42

标签: c

我正在做一些实验,看看C如何在堆栈上分配变量。我用以下代码得到了一些奇怪的行为。 C似乎正在向下增长堆栈,因此在下面的示例中,char c在short s之前的字节中分配。然后我创建一个int指针bigRandP并将其指向c占用的相同位置,因此它看到的“int”与s占用的堆栈上的空间重叠。然后我尝试将一些东西分配给int指针引用的位置。

unsigned short nameSum = 0;
unsigned char smallRand = 0;
unsigned int* bigRandP;

//The "int" pointed to by iP should overlap s
bigRandP = (unsigned int*)(&smallRand);
printf("%p %p %p\n", &nameSum, &smallRand, bigRandP);
printf("%u %u %u\n", smallRand, nameSum, *bigRandP);
*bigRandP = 0;
printf("%p %p %p\n", &nameSum, &smallRand, bigRandP);
printf("%u %u %u\n", smallRand, nameSum, *bigRandP);

0028FF1A 0028FF19 0028FF19
0 0 419430400
0028FF1A 0028FF19 0028FF00
0 0 4210788

印刷结果很有趣。不仅赋值失败(bigRandP指向的int未设置为0),int指针本身也默默地重定位指向堆栈下方的其他位置。到底是怎么回事?这是C编译器阻止我用重叠指针覆盖其他变量的方法吗?

1 个答案:

答案 0 :(得分:4)

bigRandP是指向unsigned int的指针。

您将其指向unsigned char对象,然后修改 unsigned int指向的bigRandP对象。

显然smallRandbigRandP在内存中彼此靠近存储。通过尝试修改1字节对象的sizeof (unsigned int)个字节,您破坏了指针对象本身的一部分。

底线:您的程序行为未定义。

此外,虽然这可能与您看到的行为无关,但%p格式需要void*参数。如果要打印其他类型的指针,则应将其转换为void*

printf("%p %p %p\n", (void*)&nameSum, (void*)&smallRand, (void*)bigRandP);

在所有指针具有相同表示的系统上,使用或不使用强制转换可能会“工作”,但所有系统上的强制转换版本更正确。