1. ホーム
  2. c

[解決済み] なぜ sizeof(my_arr)[0] はコンパイルして sizeof(my_arr[0]) と同じになるのでしょうか?

2022-07-11 10:58:59

質問

なぜこのコードはコンパイルできるのでしょうか?

_Static uint32_t my_arr[2];
_Static_assert(sizeof(my_arr) == 8, "");
_Static_assert(sizeof(my_arr[0]) == 4, "");
_Static_assert(sizeof(my_arr)[0] == 4, "");

最初の2つのアサートは明らかに正しいのですが、私の理解では最後の行は失敗すると思っていました。 sizeof() は整数リテラルとして評価され、配列として扱われないと理解しているからです。言い換えれば、それは次の行が失敗するのと同じ方法で失敗するでしょう。

_Static_assert(4[0] == 4, "");

興味深いことに、以下は確かにコンパイルに失敗しています(同じことをやっているはずですが?)

_Static_assert(*sizeof(my_arr) == 4, "");

error: unary '*' の型引数が不正('long unsigned int' がある)。 _Static_assert(*sizeof(my_arr) == 4, "")。

もしそれが重要なら、私はgcc 5.3.0を使用しています。

どのように解決するのですか?

sizeof は関数ではありません。のような単項演算子です。 ! または ~ .

sizeof(my_arr)[0] は次のように解析します。 sizeof (my_arr)[0] となりますが、これは単に sizeof my_arr[0] に冗長な括弧をつけただけのものです。

これはちょうど !(my_arr)[0] は、次のようにパースします。 !(my_arr[0]) .

一般にC言語では、後置演算子は前置演算子よりも優先順位が高くなります。 sizeof *a[i]++ は次のようにパースします。 sizeof (*((a[i])++)) (後置演算子 []++ が適用されるのは a が適用され、次にプリフィックス演算子 *sizeof ).

(の表現版です)。 sizeof . 型バージョンもあり、これは括弧で囲まれた型名を取ります。 sizeof (TYPE) . この場合、括弧は必須であり、また sizeof の構文の一部となります)。