0

我试图理解 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 是合法的,因为所有其他人都指的是一些未初始化的随机内存,应该会导致段错误

4

3 回答 3

2

UB 很有趣——行为是未定义的,不能保证段错误。的地址obj + 1可能是堆栈上的其他位置,无论如何都会分配给您的程序。要获得几乎可以保证的段错误,只需obj在分配之前取消引用。

于 2012-06-15T20:36:46.663 回答
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 超过任何有效值,这会导致未定义的行为。

当您的代码执行调用未定义行为的事情时,很难并且通常无法推断将要发生的事情。它是未定义的。可能会发生一些意想不到的事情。可能会发生一些不好的事情。不会发生任何不好的事情,等等。在 C 中做一些你不应该做的事情,并不意味着它会出现段错误。

于 2012-06-15T20:42:48.743 回答
0

ptr指向有效对象 ( value) 但ptr++不指向对象。*ptr因此,在指针递增后访问元素是未定义的行为。printfof*ptr可以显示随机数据,但也可能使您的程序崩溃。

于 2012-06-15T20:36:16.927 回答