malloc返回类型混乱

时间:2015-05-23 20:03:05

标签: c pointers malloc

我正在经历here并发现如果我们不包含stdlib.h,则会导致不需要的行为,转换返回值以及系统上的指针和整数大小是否不同。

下面是SO问题中给出的代码段。这是在64位机器上尝试的,其中指针和整数大小不同。

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

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

2 个答案:

答案 0 :(得分:5)

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位{{1} }}。 (这不是类型转换;它只是错误的代码,错误地将一种类型的值视为不同的类型。)那么(可能是垃圾)int值是转换int并存储在int*中。你可能丢失了返回指针的高阶低阶32位 - 但这只是其中一个可能出错的任意方式

或者p可能会将其64位结果推送到堆栈上,并且调用者可能只从堆栈中弹出32位,从而导致堆栈错位,导致所有后续执行不正确。由于历史原因,C编译器通常不使用这种调用约定,但标准允许它。

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

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

答案 1 :(得分:1)

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

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

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

那么,没有什么可以测试的吗?