Main.cファイルを取得し、Mac OSXでgcc-std = c1x -c main.cを使用してコンパイルすると、エラーなしで正常に動作します。次に、LinuxMintとRaspberry Piでまったく同じことを行いますが、どちらの場合も、「初期化要素が一定ではありません」というエラーが表示されます。
関連するコードを含む問題のある行の一例:
//STATIC GLOBAL CONSTANTS
const unsigned long long LATITUDE = (long) 3600000;
const unsigned long long LONGITUDE = (long) 1810000;
const unsigned long long MAX_COORDINATES_NUMBER = (LATITUDE-1) + LATITUDE*(LONGITUDE-1); //compiler error: initializer element is not constant
算数をさせてくれるはずですよね?それを実際の数値に置き換えるだけでうまくいきますが、そうすると面倒になります。そしてそれはとにかく私のMacでうまく動作します。 Linuxで指定しなければならないGCCのオプションはありますか(Macでは必要のない-std = c1x以外)?
C言語では、静的オブジェクトの初期化子が定数式である必要があります。 (静的オブジェクトの初期化はmain
が始まる前に行われるため、実行時の評価を行う場所はありません。)
Cのconst
キーワードは「一定」を意味するものではありませんが、単語は明らかに関連しています。 定数式は、コンパイル時に評価できるものであり、場合によっては評価する必要があります。 const
は読み取り専用を意味します。たとえば、ブロックスコープ(関数定義内)では、次のようになります。
const int r = Rand();
完全に合法です。明らかに、初期化子はコンパイル時に評価できません。 const
は、r
が初期化された後に変更できないことを意味します。
あなたが書くとき:
const unsigned long long LATITUDE = (long) 3600000;
LATITUDE
への参照は定数式ではありません。コンパイラは確かにcouldコンパイル時にそのような参照を評価できますが、C標準ではそれを要求していません。 (定数式と非定数式の間の線はどこかに描かれなければならず、言語の作者は、特別な場合をほとんど伴わずに、区別を比較的単純にすることを選択しました。)
LATITUDE
が定数式になるように、C言語couldが定義されていることは確かです。それはC++であり、私はCが同様のルールを採用することを主張しました。しかし、現在のCルールではそうではありません。つまり、静的オブジェクトの初期化子でLATITUDE
を使用することはできません。
これは、clang
(MacOSでgcc
と入力したときに呼び出されるコンパイラ)は、このエラーの診断に失敗するため、不適合である可能性が非常に高いことも意味します。 。私自身のLinuxシステムでは、-std=c11 -pedantic
を指定して呼び出すと、gcc 4.7.2はエラーを正しく診断しますが、clang3.4は診断しません。
2011 ISO C標準(1990および1999標準にも存在する)のセクション6.6パラグラフ10のこの条項のおそらくを除いて:
実装は、他の形式の定数式を受け入れる場合があります。
Clangはこの権限を利用しているため、定数式としてLATITUDE
を受け入れると考えられますが、それでも少なくともclang -std=c11 -pedantic -Wall -Wextra
からの警告が予想され、何もありません。
[〜#〜] update [〜#〜]:以下をコンパイルすると:
#include <stdio.h>
const unsigned long long LATITUDE = (long) 3600000;
int main(void) {
switch (0) {
case LATITUDE:
puts("wrong");
break;
default:
puts("ok(?)");
break;
}
}
オプション-std=c99 -pedantic
を使用したclang3.0を使用すると、次のようになります。
c.c:7:14: warning: expression is not integer constant expression (but is allowed as an extension) [-pedantic]
case LATITUDE:
^~~~~~~~
1 warning generated.
Clang 3.4では、警告は次のとおりです。
c.c:7:14: warning: expression is not an integer constant expression; folding it to a constant is a GNU extension [-Wgnu-folding-constant]
case LATITUDE:
^~~~~~~~
1 warning generated.
したがって、clangはそれが定数式ではないことを認識します。バグは、MAX_COORDINATES_NUMBER
の宣言について警告しないことです。
別の更新:
問題のコードは次のとおりです。
const unsigned long long LATITUDE = (long) 3600000;
const unsigned long long LONGITUDE = (long) 1810000;
const unsigned long long MAX_COORDINATES_NUMBER = (LATITUDE-1) + LATITUDE*(LONGITUDE-1);
最初の2つの宣言の(long)
キャストは役に立ちません。定数3600000
および1810000
は(おそらく)タイプint
です。それらをlong
に変換し、その結果を使用してタイプunsigned long long
のオブジェクトを初期化します。キャストを削除するだけです。または、より明確にしたい場合は、ULL
サフィックスを追加して、定数をunsigned long long
にします。
const unsigned long long LATITUDE = 3600000ULL;
const unsigned long long LONGITUDE = 1810000ULL;
問題は、LATITUDE
とLONGITUDE
を参照する3番目の宣言にあります。どちらも定数式ではありません。残念ながら、Cはint
以外の整数型の名前付き定数を定義する良い方法を提供していません(enum
定数にint
機能を(乱用)使用できます)。別の方法は、マクロを使用することです。これは機能します:
#define LATITUDE 3600000ULL
#define LONGITUDE 1810000ULL
const unsigned long long MAX_COORDINATES_NUMBER = (LATITUDE-1) + LATITUDE*(LONGITUDE-1);
また、MAX_COORDINATES_NUMBER
を定数式にする必要がある場合は、それをマクロにすることもできます。
#define LATITUDE 3600000ULL
#define LONGITUDE 1810000ULL
#define MAX_COORDINATES_NUMBER ((LATITUDE-1) + LATITUDE*(LONGITUDE-1))
(より大きな式でMAX_COORDINATES_NUMBER
を使用する場合、演算子の優先順位の問題を回避するために、追加の括弧が必要です。)