sizeof(my_arr)[0]がコンパイルされ、sizeof(my_arr [0])と等しいのはなぜですか?


129

なぜこのコードはコンパイルするのですか?

_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, "");

エラー:単項 '*'の型引数が無効です( 'long unsigned int'があります)_Static_assert(* sizeof(my_arr)== 4、 "");

それが重要であれば、私はgcc 5.3.0を使用しています


15
私は( sizeof( my_arr ) )[ 0 ]失敗すると思います。
Andrew Henle

最近の複製には、この構文の驚きに関する別のバリ​​エーションがあります。なぜsizeof(x)++がコンパイルされるのですか?
Peter Cordes

回答:


197

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

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構文の一部になります。)


14
sizeofが関数ではなく単項演算子であることは間違いなく知っていましたが、完全に忘れていました。おっと。詳しい説明ありがとうございます。[]が*よりも優先されるという事実は興味深いです。
bgomberg 2017年

@melpomene興味深い。sizeof単項演算子であるとは考えたこともありません。
ミュータントキーボード

5
どういう意味"... parses as sizeof (my_arr[0])"ですか?スペースを追加するだけでは、何も変わりません。
Bernhard Barker

sizeof((my_array)[0])代わりに私がお勧めします
bolov


46

sizeofには2つの「バージョン」がsizeof(type name)ありsizeof expressionます。前者は()その議論の前後にペアを必要とします。しかし、後者-式を引数として持つ-は()、その引数の周りにはありません。()引数で使用するものはすべて、sizeof構文自体の一部ではなく、引数式の一部と見なされます。

以来my_arr、オブジェクト名ではなく、型の名前としてコンパイラに知られている、あなたsizeof(my_arr)[0]のようになり、実際にコンパイラで見られるsizeof表現に適用される:sizeof (my_arr)[0]ここで、(my_arr)[0]引数式です。()周囲の配列名は純粋に不必要です。式全体はと解釈されsizeof my_arr[0]ます。これは以前のと同じsizeof(my_arr[0])です。

(つまり、以前のバージョンにsizeof(my_arr[0])は余分なペアも含まれています()。)

sizeofの構文はどういうわけか()その引数の前後にペアを必要とするというのは、かなり広範囲にわたる誤解です。この誤解は、のような表現を解釈するときに人々の直感を誤解させるものsizeof(my_arr)[0]です。


1
最初のバージョンは、マシン上で整数のサイズを一般的にチェックできるように存在します(64ビットマシンさえなかったときの後ろから!)がint、有効な式ではないため、使用できません。それを使った第二の形。
NH。

25

[]よりも優先順位が高いsizeof。だから、sizeof(my_arr)[0]同じですsizeof((my_arr)[0])

これは優先順位表へのリンクです。


8

sizeof式をパラメーターとして取るバージョンの演算子を使用しています。型を取るものとは異なり、括弧必要ありません。したがって、オペランドは単純(my_arr)[0]で、括弧は冗長です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.