LoginSignup
20
20

More than 5 years have passed since last update.

gccとclangの仕様の違い?

Posted at

ふとしたコンパイルエラーから始まった

いつもどおりC言語で簡単な計算をするプログラムを書いていました。
定数をよく使うんで関数外(つまりグローバルな定数変数として)にこんなふうに書いていたんです。

const double e = 1.602e-19;
const double k_B = 1.38e-23 / e;

研究室ではMacを使っているのでAppleがカスタマイズしたclangでコンパイルしてました(gccコマンドでclangが走るようになってた)。
このプログラムがC言語の仕様を満たしているかは自分にはわかりません。
ただ自分の感覚ではコンパイルは通るだろうと思っていました。
まぁ1回目の代入ですし…
その通りclangではコンパイルが通りました。もちろん-Wallをつけてもwarningすらもでませんでした。
ただ自宅でコンパイルするとエラーが出たのです!!!

FileName.c:xx:yy: error: initializer element is not constant
 const double k_B = 1.38e-23 / e;
                    ^

エラーメッセージはこのように出ていました。
gccのバージョンはgcc 5.3.1でした。
そこで自宅でもclangを導入してみました。
するとやはりエラーは出ません。
gccとLLVMのclangどちらかがC言語の仕様を満たしていないのでしょうか?
それとも、C言語の仕様にはこのような記述についてそもそも定義されていないのでしょうか?

結局どういうことなのか?

StackOverflowにこんな記事がありました。
その記事によると

C言語では定数表現には静的オブジェクトのための宣言が必要です(静的オブジェクトの宣言がmainの前に行われるので、任意の実行時に評価する場所がありません)。
const修飾子は明らかにconstantに関係があるように見えますが、C言語でのconst修飾子の意味は定数式を構成できるものであり、またコンパイル時に評価ができなければなりません。つまるところconstは、読み取り専用です。

となっています。
ほう、「任意の実行時に評価ができなければならない」と。
関数なんかのブロック外では記述してある順序によらずに評価できなければならないってことですかね?
確かにeconstをつけていても変数ですから、先にeの宣言が評価されてなければ、k_Bは決定できませんね。

はて?
ではなぜclangではエラーにならなかったのか?
clnagが仕様を満たしてないってことなのかな?
続きを読んでいくとこんなことが書いてありました。

This also means that clang (the compiler that, as I understand it, is the one invoked when you type gcc under MacOS) is very likely non-conforming, because it fails to diagnose this error. On my own Linux system, I find that, when invoked with -std=c11 -pedantic, gcc 4.7.2 correctly diagnoses the error, but clang 3.4 does not

やはり仕様を満たしていないような感じなことが書いてあるようなきがします(翻訳めんどくさくなってごめんなさい)。
うーん…
どうしたものか…
ここはgccに合わせたほうが良さそうな感じかな。
clangがこれをエラーにする可能性も十二分にあるし。
そんなわけで、あまりこんな書き方をする方はいらっしゃらないと思いますが、constは定数じゃなくて、read onlyを意味する修飾子だってことを理解しないとダメですね。

20
20
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
20