Cの定数式を構成するものの詳細は?
-
28-10-2019 - |
質問
Cは、少なくとも3つのレベルの「一定の表現」を定義します。
- 定数式(修飾なし)
- 算術定数式
- 整数定数式
6.6段落3の読み取り:
定数式には、代入、インクリメント、デクリメント、関数呼び出し、 またはコンマ演算子(ただし、そうでない部分式に含まれている場合を除く) 評価済み。
つまり、
1,2
は一定の表現ではないということですか?段落8の内容:
算術定数式は算術型を持ち、 整数定数、浮動定数、列挙定数、文字であるオペランド 定数、および式のsizeof。算術定数式のキャスト演算子 のオペランドの一部を除いて、算術型を算術型に変換するだけです。 結果が整数定数であるsizeof演算子。
(union { uint32_t i; float f; }){ 1 }.f
のオペランドは何ですか?1
がオペランドの場合、これはおそらく算術定数式ですが、{ 1 }
がオペランドの場合、明らかにそうではありません。編集:別の興味深い所見:7.17段落3では、
offsetof
の結果がsize_t
型の整数定数式である必要がありますが、私が知る限り、offsetof
の標準実装はそうではありません。標準では整数定数式である必要があります。もちろん、これは、実装が(6.6段落10の下で)他の形式の定数式を受け入れること、またはポインター減算ではなく、offsetof
マクロを__builtin_offsetof
として実装することが許可されているため問題ありません。ただし、この観察の本質は、整数定数式が必要なコンテキストでoffsetof
を使用する場合は、実装によって提供されるマクロを使用する必要があり、独自のマクロをロールする必要がないということです。
解決
あなたの読書に基づくと、1,2
は一定の表現ではありません。なぜそうではないのかわかりませんが、そうではないことに同意します(おそらくそうあるべきであるという事実にもかかわらず)。
6.5.2は、複合リテラルを接尾辞演算子として指定します。だから ジェネラコディセタグプレ
オペランドは、(union { uint32_t i; float f; }){ 1 }
演算子に対するf
および.
です。最初の引数はunion
型であるため、算術定数式ではありませんが、定数式です。
更新:これは標準の別の解釈に基づいていました。
私の以前の推論は、(union { uint32_t i; float f; }){ 1 }.f
が一定の式の基準を満たしているため、一定の式であるというものでした。それでも定数式の基準(6.6段落3)を満たしていると思いますが、標準タイプの定数式(整数、算術、またはアドレス)のいずれでもないため、6.6段落までの定数式の対象となるだけです。 10、これにより実装定義の定数式が可能になります。
私もあなたの編集に取り掛かるつもりでした。 offsetof
の「ハック」実装は定数式であると主張するつもりでしたが、上記と同じだと思います。定数式(および場合によってはアドレス定数)の基準を満たしていますが、整数定数式ではありません。したがって、6.6段落10以外では無効です。
他のヒント
1,2
が定数式の場合、次のようなコードをコンパイルできます。
ジェネラコディセタグプレ
それが本当の理由かどうかはわかりませんが、1,2
を定数式に変換するよりも、この(一般的な?)間違いに対してエラーを出すことが重要であると考えられていたと思います。
更新:R。がコメントで指摘しているように、VLAの導入以降、コードについてのコードはコンパイラエラーではなくなりました。