为什么这段代码会在64位架构上发生段错误但在32位上运行良好?

use*_*er7 108 c pointers segmentation-fault

我遇到了以下C拼图:

问:为什么以下程序会在IA-64上发生段错误,但在IA-32上运行良好?

  int main()
  {
      int* p;
      p = (int*)malloc(sizeof(int));
      *p = 10;
      return 0;
  }
Run Code Online (Sandbox Code Playgroud)

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

Fle*_*exo 125

演员int*掩盖了这样一个事实:没有适当#include的返回类型malloc被认为是int.IA-64恰好具有sizeof(int) < sizeof(int*)明显的问题.

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

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

  • @ user7:"我们有一个指针p(大小为64),指向32位内存" - 错误.由malloc分配的块的地址是根据`void*`的调用约定返回的.但是调用代码认为函数返回`int`(因为你选择不告诉它),所以它试图根据`int`的调用约定读取返回值.因此`p`确实*不一定指向分配的内存.它恰好适用于IA32,因为`int`和`void*`的大小相同,并以相同的方式返回.在IA64上,您得到错误的值. (16认同)
  • @WTP - 这是在C++中始终使用`new`并始终使用C编译器而不是C++编译器编译C的一个很好的理由. (11认同)
  • @ user7 - 这就是规则.如果不知道任何返回类型,则假定为"int" (6认同)
  • 没有正确的#include,为什么假设malloc的返回类型是int? (5认同)
  • @vlad-更好的主意是总是声明函数,而不是完全出于这个原因而依赖隐式声明。(而不是强制从`malloc`返回) (2认同)
  • @ user7有关“ int”类型的返回约定,请参见[here](http://c-faq.com/decl/implfdecl.html) (2认同)

pax*_*blo 31

很可能因为你没有包含头文件malloc而且,虽然编译器通常会警告你这一点,你明确地转换返回值的事实意味着你告诉它你知道你在做什么.

这意味着编译器期望int返回malloc一个然后从中转换为指针.如果它们的尺寸不同,那将会让你感到悲伤.

这就是为什么你从来不投的mallocC中的回报void*,这回报会隐式转换为正确类型的指针(除非你有没有包含在这种情况下,它可能会提醒你的潜在不安全内部-的头指针转换).

  • @ user7:没有#include <stdlib.h>,C编译器假定malloc的返回值是一个int. (4认同)
  • @ user7:可以*转换void指针*,但在C中不需要它,因为`void*`可以隐式转换为任何其他指针类型.`int*p = malloc(sizeof(int))`如果正确的原型在范围内则有效,如果不是则失败(因为那时结果假定为`int`).使用强制转换时,两者都会编译,后者会在`sizeof(int)!= sizeof(void*)`时导致错误. (4认同)
  • @ user7但是如果不包含`stdlib.h`,编译器就不知道`malloc`,也不知道它的返回类型.所以它只是假设`int`为默认值. (2认同)

cur*_*guy 9

这就是为什么你永远不会编译没有关于缺少原型的警告.

这就是你永远不会在C中使用malloc返回的原因.

C++兼容性需要强制转换.没有理由(阅读:没有理由在这里)省略它.

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

  • 如果我的C代码与C++"兼容",我为什么要关心呢?我不在乎它是否与perl,java或Eiffel兼容...... (21认同)
  • 如果你保证有人下线不会看你的C代码然后去,嘿我要用C++编译器编译它,因为这应该工作! (3认同)
  • 这是因为大多数C代码可以**简单地与C++兼容. (2认同)