我试图理解C中的void指针类型转换。我写了一个程序来尝试创建一个分段错误,但我没有得到它。有人可以向我解释为什么
代码:
#include <stdio.h>
typedef unsigned long U32;
int main()
{
void *obj;
U32 value = 25;
U32* ptr;
printf("*(ptr) : %lu\n", *(ptr));
obj = &value;
ptr = &value;
ptr++;
printf("*(U32 *)(obj) : %lu\n", *(U32 *)(obj));
printf("*((U32 *)(obj) + 1) : %lu\n", *((U32 *)(obj) + 1));
printf("*(U32 *)((U32 *)(obj) + 1) : %lu\n", *(U32 *)((U32 *)(obj) + 1));
printf("*(ptr) : %lu\n", *(ptr));
return 0;
}
输出:
*(ptr) : 458998657
*(U32 *)(obj) : 25
*((U32 *)(obj) + 1) : 3215085752
*(U32 *)((U32 *)(obj) + 1) : 3215085752
*(ptr) : 3215085752
我看到它的方式只有第二个printf是合法的,因为所有其他人都指的是一些未初始化的随机存储器并且应该导致seg错误
答案 0 :(得分:2)
UB很有趣 - 行为未定义,不保证段错误。 obj + 1
的地址可能是堆栈中的其他位置,无论如何都会分配给您的程序。要获得几乎保证的段错误,只需在分配obj
之前取消引用。
答案 1 :(得分:1)
U32* ptr;
printf("*(ptr) : %lu\n", *(ptr));
ptr
未初始化,因此取消引用它是未定义的行为,
obj = &value;
ptr = &value;
ptr++;
printf("*(U32 *)(obj) : %lu\n", *(U32 *)(obj));
好的,只要obj
指向有效的U32(并且U32必须是无符号长,因为您使用%lu作为printf格式)
printf("*((U32 *)(obj) + 1) : %lu\n", *((U32 *)(obj) + 1));
您尝试取消引用指向一个U32指向任何有效位置的指针,因此它是未定义的行为。
printf("*(U32 *)((U32 *)(obj) + 1) : %lu\n", *(U32 *)((U32 *)(obj) + 1));
与上述相同。
printf("*(ptr) : %lu\n", *(ptr));
由于你增加了ptr
,它将一个U32指向任何有效的东西,这会导致未定义的行为。
当你的代码执行调用undefined behavior的事情时,真的很难并且通常无法推断会发生什么。这是未定义的。意想不到的事情可能发生。可能发生了一件坏事。没有什么不好的事情可能发生,等等。在C中做一些你不应该做的事情,并不意味着它会发生段错误。
答案 2 :(得分:0)
ptr
指向有效对象(value
),但ptr++
未指向对象。因此,在指针增量之后访问元素*ptr
是未定义的行为。 printf
的{{1}}可以显示随机数据,但也会导致程序崩溃。