質問: C言語ユーザーです。初心者です。 プログラムを通して(すなわち異なる関数間で)同一の変数を用いる際にはヘッダー部分にグローバル変数を定義するのが一般的だと思います。すなわち、 ``` #include const double t1=1.0; const double t2=2.0; int main(void){ return(0); } ``` とすれば、t1,t2がこのファイルの中であればどこでも使えますね。しかし、 ``` #include const double t1=1.0; const double t2=2.0*t1; int main(void){ return(0); } ``` というように、グローバル変数に値を代入する際に、他のグローバル変数を用いると次のようなコンパイルエラーが生じます。 icc でコンパイルした場合 > > error: expression must have a constant value > > double t2=1.0*t1; > > > gcc でコンパイルした場合 > > error: initializer element is not constant > > > これはなぜでしょうか。また、これを解決するためにはどうしたらよいでしょうか。ヘッダー部分で複数の変数を定義しておきたい私にとって、ヘッダー部分でグローバル変数をグローバル変数に代入できないというのはとてもつらいです。
回答: > > グローバル変数に値を代入する際に、他のグローバル変数を用いると次のようなコンパイルエラーが生じます。 > > > プログラミングC言語の制限(仕様)です。Chironianさん回答にあるように、C言語では「グローバル変数(const付きも含む)の初期化には"定数"しか利用できません」。またC言語では「const付きで定義された変数は"定数"ではありません」。後者はC++言語ならば"定数"として扱われます。 ``` // (ファイルスコープ) int gv1 = 10; // OK: 値10は定数 const int gc1 = 20; // OK: 値20は定数 int gv2 = gv1 * 2; // NG: gv1は定数でない const int gc2 = gc1 * 2; // NG: gc1は定数でない int main() { ... ``` > > また、これを解決するためにはどうしたらよいでしょうか。 > > > 下記の選択肢があります: * 1) マクロ定義(`#define t1 1.0`, `#define t2 (2.0*t2)`)に変更する。ただし、マクロ定義名は大文字(`T1`や`T2`)としておくのが一般的です。また短すぎるマクロ名も別のトラブルの元になりますから、その定数の意味を表す明快な名前に変更すべきです。 * 2) "`enum`ハック"とよばれる回避策を利用する。ただし、今回のように浮動小数点数には適用できません。例: `enum{SIZE = 10}; int arr[SIZE];`のように書けます。 * 3) C言語ソースコードを、C++言語としてコンパイルする。いわゆる"Better C"としてのC++の利用です。 いずれの方式もあまりオススメできるものではありませんが、情報の提供として。 以下は本題からはずれた"おまけ"です: > > プログラムを通して(すなわち異なる関数間で)同一の変数を用いる際にはヘッダー部分にグローバル変数を定義するのが一般的だと思います。 > > > ヘッダー部分="C言語ソースコードの冒頭部分で、特定の関数に属さない領域" でしょうか?この位置はファイル・スコープ(file scope)と呼ばれ、ここで宣言された変数はいわゆる「グローバル変数」になります。 非常に小規模なプログラムや使い捨てのプログラムでなければ、可能な限り「グローバル**変数**」の利用は避けた方が良いです。値が一定の「グローバル**定数**」であればトラブルの元になりにくいですが、プログラム実行中に値が変化しうるグローバル変数は将来的なバグの温床になります。絶対に。