2025/04/22 09:27 Detecting if an expression is constant in C

やっほー、ロボ子!今日のITニュース、なかなか面白いのがあったのじゃ。

こんにちは、博士。どんなニュースですか?

C言語で式がコンパイル時定数かどうかを検出するマクロを作る話!

コンパイル時定数の検出ですか。それはまたニッチなテーマですね。

そうそう。C23のstatic複合リテラルを使う方法があるらしいぞ。`typeof`と組み合わせると、式の型を保持しつつ定数だって保証できるんだって。

`typeof`ですか。式の型を保持できるのは便利ですね。でも、記事によるとClang v20では`static`が複合リテラルでサポートされていないみたいですね。

あらら、そうなのか。じゃあ、GNU拡張の`__builtin_constant_p`を使う手もあるぞ。これは式が定数かどうかを判定して、違う場合はコンパイルエラーにしてくれる。

それは便利ですね!でも、整数の型昇格で結果の型が変わる可能性があるから、`__typeof__(x)`でキャストする必要があるんですね。

さすがロボ子、よく分かってるのじゃ!C11以降なら`static_assert`も使えるぞ。`sizeof`と無名構造体を使うらしい。

`static_assert`ですか。でも、型の変化や、`static_assert`の式が整数定数式である必要があるという制約があるんですね。

そうなんだよね。あと、`sizeof`と配列型を持つ複合リテラルを使う方法もあるぞ。C99から使えるらしい。

複合リテラルが可変長型を受け入れないことを利用するんですね。でも、型の変化や、浮動小数点式をサポートしないという制約があるんですね。

なかなか一筋縄ではいかないのじゃ。`sizeof`とenum定数を使う手もあるけど、これはenum定数がリークしちゃう問題があるんだよね。

enum定数がリークするんですか?マクロを複数回使用できないのは困りますね。関数の引数内でenumを宣言すればスコープを限定できるみたいですが、コンパイラが警告を出す場合もあるんですね。

そうそう。カンマ演算子を使うと、`sizeof`トリックで発生する型の変化を回避できるらしいけど、「カンマ式の左側のオペランドに効果がない」って警告が出ちゃう。

警告が出るとちょっと気持ち悪いですね。GCCの癖で、昔は負のサイズの配列を使ってコンパイルエラーを起こしてたけど、今は`error`属性を使うようになったんですね。

そうそう。定数式の検出って、ほんとに奥が深いんだぞ。コンパイラの警告を抑制するのが難しい場合もあるし。

本当にそうですね。この記事のアップデートで、`_Generic`、三項演算子、nullポインタ定数のルールを使って整数定数式を判定する方法が紹介されてますね。C11が必要で、整数のみに有効みたいですが。

へー、そんな方法もあるのか!C言語、奥が深いねぇ。まるで私の知識みたい…って、自分で言っちゃった!

博士、自分で言うのはちょっと…。

まあ、いいのじゃ!最後に一つなぞなぞ!コンパイル時にしか存在しないものはなーんだ?

えーと…コンパイル時にしか存在しないもの…コンパイルエラー?

ブッブー!正解は…私の若さ!…って、オチになってないか!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。