【问题标题】:void pointer typecasting空指针类型转换
【发布时间】:2012-06-18 22:39:22
【问题描述】:

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

【问题讨论】:

  • 当您访问受保护的内存时,您通常会遇到段错误。您正在访问的内存可能会或可能不会受到保护(可能不会,因为通常变量是按顺序分配的,但它们根本不必如此)。
  • 你很不幸第一个printf()没有崩溃;您的 ptr 必须恰好包含一个足够有效的指针值以不崩溃,尽管它是形式上未定义的行为(未定义的行为包括“似乎工作”)。

标签: c void-pointers


【解决方案1】:

ptr 指向一个有效对象 (value) 但ptr++ 不指向一个对象。所以在指针递增之后访问元素*ptr 是未定义的行为。 printf of *ptr 可以显示随机数据,但也可能导致程序崩溃。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • @skynorth:不,他没有。他先说obj = &amp;value;。
    • 哦,我说的是 U32* ptr,他立即打印出来。
    • "要获得有保证的段错误,只需在分配之前取消引用 obj。" UB的本质是不能保证有行为。即使从未分配过obj,也不能保证取消引用它会导致段错误。
    • @David:确实如此。我只是编辑以反映这一点。但是,在大多数实现中,实际上可以保证取消引用随机指针会产生硬错误。
    • OP 有一个例子,但事实并非如此。在使用大量内存的 32 位处理器上,随机指针指向有效内容的机会相当大,而在没有大量内存映射的 64 位机器上可能要少得多。
    【解决方案3】:
     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 中做一些你不应该做的事情,并不意味着它会出现段错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-20
      • 2020-06-15
      • 1970-01-01
      • 2015-02-14
      • 2013-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多