我正在做一些实验,看看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编译器阻止我用重叠指针覆盖其他变量的方法吗?
答案 0 :(得分:4)
bigRandP
是指向unsigned int
的指针。
您将其指向unsigned char
对象,然后修改 unsigned int
指向的bigRandP
对象。
显然smallRand
和bigRandP
在内存中彼此靠近存储。通过尝试修改1字节对象的sizeof (unsigned int)
个字节,您破坏了指针对象本身的一部分。
底线:您的程序行为未定义。
此外,虽然这可能与您看到的行为无关,但%p
格式需要void*
参数。如果要打印其他类型的指针,则应将其转换为void*
:
printf("%p %p %p\n", (void*)&nameSum, (void*)&smallRand, (void*)bigRandP);
在所有指针具有相同表示的系统上,使用或不使用强制转换可能会“工作”,但所有系统上的强制转换版本更正确。