web-dev-qa-db-ja.com

このコードは64ビットアーキテクチャではセグメンテーション違反ですが、32ビットでは正常に動作するのはなぜですか?

私は次のCパズルに出会いました:

Q:IA-64では次のプログラムがセグメンテーション違反になりますが、IA-32では正常に動作するのはなぜですか?

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

64ビットマシンのintのサイズは、ポインターのサイズと同じでない場合があることを知っています(intは32ビットで、ポインターは64ビットです)。しかし、これが上記のプログラムにどのように関係しているかはわかりません。何か案は?

107
user7

_int*_へのキャストは、適切な_#include_がない場合、mallocの戻り値の型がintであると想定されるという事実を隠しています。 IA-64にはsizeof(int) < sizeof(int*)が含まれているため、この問題が明らかになります。

(未定義の動作のため、sizeof(int)==sizeof(int*)が真であるプラットフォームでも失敗する可能性があることに注意してください。たとえば、呼び出し規約が整数よりもポインターを返すために異なるレジスタを使用した場合)

comp.lang.c FAQ には なぜmallocからの戻り値をキャストする必要がないのか、潜在的に悪い についてのエントリがあります。

124
Flexo

最も可能性が高いのは、含まないmallocのヘッダーファイルであり、コンパイラが通常これを警告する一方で、戻り値を明示的にキャストしているという事実は、 「何をしているのか知っていると伝えている。

これは、コンパイラがintからmallocが返されることを期待していることを意味しています。それらが異なるサイズである場合、それはあなたを悲しませます。

これがnevermallocをCにキャストする理由です。void*が返すことは暗黙的に正しい型のポインターに変換されます(ヘッダーを含めていない場合は、安全でない可能性のあるintからポインターへの変換について警告しているはずです)。

31
paxdiablo

これが、プロトタイプの欠落に関する警告なしにコンパイルしない理由です。

これが、Cでmallocリターンをキャストしない理由です。

C++との互換性のためにキャストが必要です。省略する理由はほとんどありません(ここでは理由はありません)。

C++の互換性は常に必要なわけではなく、いくつかのケースではまったく不可能ですが、ほとんどの場合、非常に簡単に実現できます。

9
curiousguy