【问题标题】:malloc return typecasting confusionmalloc 返回类型转换混乱
【发布时间】:2015-08-05 16:16:13
【问题描述】:

我正在查看here,发现如果我们不包含 stdlib.h、强制转换返回值以及系统上的指针和整数大小不同,malloc 可能会导致不需要的行为。

下面是那个 SO 问题中给出的代码 sn-p。这是在指针和整数大小不同的 64 位机器上尝试的。

int main()
{
      int* p;
      p = (int*)malloc(sizeof(int));
      *p = 10;
      return 0;
}

如果我们不包含stdlib.h,编译器将假定malloc 返回类型为int,并且将其转换并分配给不同大小的指针可能会导致不需要的行为。 但我的问题是为什么将 int 转换为 int* 并将其分配给不同大小的指针会导致问题。

【问题讨论】:

  • 首先,它被(隐式)转换为int,因此从8字节截断为4字节。除非原始 8 字节值的前 4 个字节(更重要的)包含全零,否则会丢失一些信息。将结果转换回 int* 不会检索到该信息,从而为您留下一个“虚假”指针。
  • 当编译器遇到“int *p”声明时,它会在声明时确定该指针需要 8 个字节(例如)的存储空间。接下来,在运行时,当 malloc 被执行时,它返回一个默认的“int”,因为不存在函数原型声明(由于缺少 stdlib.h)。当新分配的内存的地址(8 字节)存储在 int(4 字节)中并返回给您时,可能会失去意义。现在,此时如果您尝试将 int 强制转换为 int * 并将其分配给您的指针 'p' ...可能会出现意外行为。

标签: c pointers malloc


【解决方案1】:

几乎,如果在调用之前没有给出原型,任何函数都会导致未定义的行为,除非它的原型是int function(int x);。

很明显,如果指针的大小大于int 的大小并且malloc() 由于隐式声明而返回int,则返回的地址可能不是真实地址,因为例如,可能无法用更少的位来表示它。

取消引用它将是未定义的行为,顺便说一下,您无法测试,因为它是未定义的,您希望发生什么?未定义!!!

那么,那里没有什么可测试的?

【讨论】:

    【解决方案2】:
    int main()
    {
          int* p;
          p = (int*)malloc(sizeof(int));
          *p = 10;
          return 0;
    }
    

    根据 C99 和 C2011 规则,在没有可见声明的情况下调用 malloc 是违反约束,这意味着符合标准的编译器必须发出诊断。 (这几乎就像 C 说某些东西是“非法的”一样。)如果你的编译器没有警告调用,你应该找出使用什么选项来让它这样做。

    根据 C90 规则,调用没有可见声明的函数会导致编译器假定该函数实际上返回了 int 类型的结果。由于malloc 实际上是用void* 的返回类型定义的,所以行为是未定义的;编译器不需要对其进行诊断,但标准并没有明确说明评估调用时会发生什么。

    在实践中通常发生的是编译器生成代码好像 malloc 被定义为返回 int 结果。例如,malloc 可能会将其 64 位 void* 结果放入某个特定的 CPU 寄存器,而调用代码可能假定该寄存器包含 32 位 int。 (这不是类型转换;它只是错误的代码,它错误地将一种类型的值视为另一种类型。)然后(可能是垃圾)int 值转换为int* 并存储在 p 中。您可能丢失返回指针的高位或低位 32 位——但这只是它可能出错的任意多种方式中的一种。

    或者malloc 可能会将其 64 位结果压入堆栈,而调用者可能仅从堆栈中弹出 32 位,从而导致堆栈未对齐,从而导致所有后续执行不正确。由于历史原因,C 编译器通常不使用这种调用约定,但标准允许。

    如果int、void* 和int* 的大小恰好都相同(因为它们通常在 32 位系统上),则代码可能会工作 - 但即使这样也不能保证。例如,调用约定可能使用一个寄存器返回int 结果,使用不同的寄存器返回指针结果。同样,大多数现有的 C 调用约定允许旧的错误代码做出这样的假设。

    调用malloc 需要#include <stdlib.h>,即使某些编译器可能不会强制执行该要求。添加#include(并删除演员表)比花时间考虑如果不这样做会发生什么要容易得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-18
      • 1970-01-01
      • 1970-01-01
      • 2012-01-07
      • 2013-02-13
      • 1970-01-01
      相关资源
      最近更新 更多