为什么此代码段错误在64位体系结构上却在32位体系结构上能正常工作?


112

我遇到了以下C难题:

问:为什么以下程序在IA-64上出现段错误,但在IA-32上却可以正常工作?

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

我知道int64位计算机上的大小int可能与指针的大小不同(可能是32位,而指针可能是64位)。但是我不确定这与上面的程序有什么关系。有任何想法吗?


50
有点像stdlib.h不被列入愚蠢的事情吗?
user786653 2011年

3
这段代码可以在我的64位计算机上正常运行。如果您#include stdlib.h(对于malloc),它甚至会在没有警告的情况下进行编译
mpenkov 2011年

1
天哪!@ user786653钉了重要的一点。使用#include <stdlib.h>,可以找到,但这不是问题。

8
@delnan-尽管它不必那样工作,但它可能会在平台上合法失败sizeof(int) == sizeof(int*),例如,如果int在所使用的调用约定中通过不同的s 返回了指针,则返回了该指针。
柔印

7
在C99环境中,编译器应至少为您提供有关的隐式声明的警告malloc()。海湾合作委员会说:warning: incompatible implicit declaration of built-in function 'malloc'也是。
乔纳森·莱夫勒

Answers:


130

演员以int*掩盖一个事实,即没有正确#include的返回类型malloc被假定为是int。IA-64碰巧有sizeof(int) < sizeof(int*)这个问题,很明显。

(还请注意,由于行为未定义,即使在sizeof(int)==sizeof(int*)保持true 的平台上,它仍然可能会失败,例如,如果调用约定使用了不同于整数的指针来返回指针)

comp.lang.c常见问题有一个条目讨论为什么铸造从返回malloc永远不会需要和可能较坏


5
没有正确的#include,为什么将malloc的返回类型假定为int?
user7 2011年

11
@WTP-这是始终new在C ++中使用并且始终使用C编译器而不是C ++编译器编译C的一个很好的理由。
柔印

6
@ user7-这就是规则。int如果未知,则假定为任何返回类型
Flexo

2
@vlad-更好的主意是始终出于这个原因而始终声明函数,而不是依赖隐式声明。(而不是强制返回malloc
柔印

16
@ user7:“我们有一个指针p(大小为64),它指向32位内存” –错误。malloc分配的块的地址根据a的调用约定返回void*。但是调用代码认为该函数返回了int(因为您选择了不告诉它),因此它尝试根据的调用约定读取返回值int。因此,p没有必要指向分配的内存。恰好对IA32有效,因为an int和a void*的大小相同,并且以相同的方式返回。在IA64上,您得到错误的值。
史蒂夫·杰索普

33

最有可能的原因是,您没有包括和的头文件malloc,而编译器通常会警告您,而您显式转换返回值的事实意味着您正在告诉它您知道自己在做什么。

这意味着编译器期望int返回malloc,然后将其从中转换为指针。如果它们的大小不同,那将使您感到悲伤。

这就是为什么您从不将返回值强制转换为mallocC的void*原因。返回的值将隐式转换为正确类型的指针(除非您没有包含标头,在这种情况下,它可能会警告您可能不安全的int-指针转换)。


很抱歉,您听起来很幼稚,但我一直假设malloc返回一个可以转换为适当类型的void指针。我不是C程序员,因此希望了解更多细节。
user7 2011年

5
@ user7:如果没有#include <stdlib.h>,则C编译器会假定malloc的返回值为int。
sashang 2011年

4
@ user7:void指针可以被铸造,但它并不需要在C作为void *可以转换为任何其它指针类型隐含。int *p = malloc(sizeof(int))如果合适的原型在范围内,则可以工作,否则就失败(因为结果被假定为int)。使用强制转换时,两者都将编译,而后者会在时导致错误sizeof(int) != sizeof(void *)

2
@ user7但是,如果不包含stdlib.h,则编译器将不知道malloc其返回类型。因此,它仅假定int为默认值。
Christian Rau

10

这就是为什么您永远不会在没有关于缺少原型的警告的情况下进行编译的原因。

这就是为什么您永远不会在C中强制执行malloc返回的原因。

C ++兼容性需要强制类型转换。没有什么理由(请阅读:这里没有理由)忽略它。

并非总是需要C ++兼容性,在某些情况下根本不可能实现,但在大多数情况下很容易实现。


22
为什么我到底会关心我的C代码是否与C ++“兼容”?我不在乎它是否与Perl或Java或Eiffel或...兼容
Stephen Canon

4
如果您保证有人不会看您的C代码,那么我将使用C ++编译器对其进行编译,因为这应该可行!
史蒂文·卢

3
这是因为大多数C代码可以简单地与C ++兼容。
curiousguy11 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.