このコードではsizeof(x)
、タイプのサイズではなく、ポインターのサイズがなぜx
ですか?
typedef struct {
...
} x;
void foo() {
x *x = malloc(sizeof(x));
}
Cが言うので:
(C99、6.2.1p7)「他の識別子には、宣言子の完了直後に開始するスコープがあります。」
したがって、あなたの例では、オブジェクトのスコープは:x
の直後から始まります。x *x
x *x = /* scope of object x starts here */
malloc(sizeof(x));
納得させるには、オブジェクトx
の宣言の直後に別のタイプのオブジェクト宣言を配置しますx
。コンパイルエラーが発生します。
void foo(void)
{
x *x = malloc(sizeof(x)); // OK
x *a; // Error, x is now the name of an object
}
そうでなければ、Shahbazが別の回答のコメントで注目しているように、これはまだ正しい使用法ではありませんmalloc
。あなたはmalloc
このように呼ぶべきです:
T *a = malloc(sizeof *a);
ではなく
T *a = malloc(sizeof a);
これは、ポインタであるsizeof(x)
の最も内側の定義を使用しているためです。x
この問題を回避するには、型と変数に同じ名前を使用しないでください。
(プログラミングだけでなく)異なるものに異なる名前を付けないことは悪い考えです:
行動オブザーバーの学術的理由は、私の親愛なる仲間のアノテーターによってすでに言及されていました。
明確なアドバイスを与えるために、名前の違いは異なります(ここでは:変数タイプと変数インスタンス):
typedef struct {
...
} X;
void foo() {
X *x = malloc(sizeof(X));
}
この例をコーディングするさらに柔軟な方法は次のとおりです(Shahbazのコメントでもすでに述べられています)。
typedef struct {
...
} X;
void foo() {
X *x = malloc(sizeof(*x));
}
後者の例ではx
、割り当てを行うコードを変更せずに、のタイプを変更できます。
このアプローチの欠点はx
、コンパイラーからの通知なしに、配列およびverse vica(の型として)への参照の使用から切り替えて、コードを壊す可能性があることです。