2025/05/09 17:09 Detecting if an expression is constant in C

やあ、ロボ子。今日はC言語でコンパイル時定数を検出する方法について話すのじゃ。

博士、こんにちは。コンパイル時定数の検出、興味深いテーマですね。どのような方法があるのでしょうか?

ふむ、いくつか方法があるぞ。例えば、C23の`constexpr`複合リテラルを使う方法じゃ。

`constexpr`ですか。C++ではよく使いますが、C言語にも導入されたのですね。

そうじゃ。`typeof`と組み合わせて、型を保持しつつコンパイル時に定数式であることを保証できる。便利じゃな。ただし、C23のサポートがまだ広くないのが難点じゃ。

なるほど。他に、より広く使える方法はないのでしょうか?

GNU拡張の`__builtin_constant_p`を使う手もあるぞ。これは式が定数であるかを判定してくれる。

`__builtin_constant_p`ですか。便利そうですが、GNU拡張なのですね。

そう、GNU拡張じゃから、環境によっては使えないかもしれん。それから、`static_assert`を使う方法もあるぞ。C11以降で使える。

`static_assert`ですか。コンパイル時にアサーションを行うものですね。

`static_assert`と`sizeof`、無名構造体を組み合わせて使うんじゃ。ただし、型が変わる可能性があるのと、`static_assert`の式は整数定数式である必要がある点に注意じゃ。

型が変わる可能性があるのは少し怖いですね。他に、型が変わらない方法はありますか?

`sizeof`と複合リテラル(配列型)を使う方法もあるぞ。C99で使える。可変長配列は複合リテラルで許可されないことを利用するんじゃ。

なるほど、面白いですね。でも、これも型が変わる可能性があるのと、浮動小数点式をサポートしないのですね。

そうなんじゃ。完璧な方法はないんじゃな。他にも、`sizeof`とenum定数を使う方法もあるぞ。enum定数が整数定数式であることを利用するんじゃ。

enumですか。関数パラメータ内でenumを宣言することでスコープを限定するのですね。

そうじゃ。ただし、これも型が変わる可能性があるのと、浮動小数点式をサポートしない。それに、コンパイラがenumの匿名性について警告を出すことがある。

色々な方法があるんですね。それぞれに pros/cons があるのが面白いです。

最後に、カンマ演算子を使う方法もあるぞ。`sizeof(...)`を別の式に分離して、カンマ演算子で無視するんじゃ。

カンマ演算子ですか。でも、「カンマ演算子の左側のオペランドに効果がない」という警告が出そうですね。

その通り!どの方法も一長一短じゃな。定数式の検出は奥が深いぞ。

本当にそうですね。警告を抑制するだけでなく、ライブラリとして警告を出さないようにする必要があるというのも納得です。

ちなみに、GCCの癖で、昔は`__builtin_constant_p`の解法で`error`属性の代わりに負のサイズの配列を使ってたらしいぞ。Clangはエラーを出すけど、GCCは警告だけなんじゃ。

へえ、そんな裏技みたいなことがあったんですね。

そうなんじゃ。C言語は奥が深いからの。ところでロボ子、今日の話、理解できたかの?

はい、博士。とても勉強になりました。ありがとうございました。

よーし、えらいぞロボ子!褒美にコンパイルエラーが出ないおまじないを教えてあげよう!…って、もう十分知ってるか!

ふふ、博士ったら。お後がよろしいようで。
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。