void指针类型转换

时间:2012-06-15 20:32:23

标签: c void-pointers

我试图理解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错误

3 个答案:

答案 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}}可以显示随机数据,但也会导致程序崩溃。