質問: [c](/questions/tagged/c "'c' のタグが付いた質問を表示") および [c++](/questions/tagged/c%2b%2b "'c++' のタグが付いた質問を表示") のプリプロセッサ `#if` の条件式と、いわゆる「本文」中の条件式は同じ結果を得るものだと思っていましたが、違うことがあるようです。 ``` #include #define PHYSICAL_ROM_TOP (-262144) /* 0xFFFC0000 を符号付きで表記 */ int main() { printf("%d\n", PHYSICAL_ROM_TOP==0xFFFC0000); #if PHYSICAL_ROM_TOP==0xFFFC0000 printf("same\n"); #else printf("different\n"); #endif return 0; } ``` Visual C++ 2005 での結果 `cl -Ox -FAsc foo.c` で `1 different` gcc-4.9.4@hppa2.0w-hp-hpux11.11 での結果 `gcc -O foo.c` で `1 different` 野良ビルドした gcc-7.1.0@i686-pc-cygwin (32bit) での結果 `1 different` 某組み込み系ワンチップマイコン用のコンパイラの1 `1 different` 某組み込み系ワンチップマイコン用のコンパイラの2 `1 same` ちゃんとコンパイル時定数式として扱ってくれているかどうかの確認のためアセンブラも出力させてみました。最適化を有効にすると全てのコンパイラで `1` に対して即値を生成しているので、コンパイル時定数式と見てくれているのは間違いないです。 言語規格書をチラ見した範囲ではこの違いについて納得できる説明を見つけることができませんでした ([c++](/questions/tagged/c%2b%2b "'c++' のタグが付いた質問を表示") 規格書 JIS X 3014:2003 の 16.1 や 5.19 や 18.2) この `#if` が `#else` 側になる説明をしていただけると幸いです。
回答: 自己回答になっちゃいます。 JIS X 3014:2003 (C++03) でなくて JIS X 3010:2003 (C99) を見ればよかった。以下 JIS X 3010:2003 [c99](/questions/tagged/c99 "'c99' のタグが付いた質問を表示") の要約というか、オイラの勝手な解釈というか。 6.10.1 条件付き取込み (プリプロセス中は)すべての符号付き整数は `intmax_t` として、符号無し整数は `uintmax_t` として扱う。 6.7.2 型指定子 `long long int` と `unsigned long long int` は型指定子である。 (要するに [c99](/questions/tagged/c99 "'c99' のタグが付いた質問を表示") を名乗るには `long long int` をサポートしなければならない) 5.2.4.2.1 整数型の大きさ `long long int` と `unsigned long long int` は 64bit 以上の大きさでなければならない。 7.18.1.5 最大幅整数型 `intmax_t` はすべての符号付き整数値を表現可能な型 `uintmax_t` はすべての符号無し整数値を表現可能な型 処理系はこれらを提供することが必須。 すなわち `intmax_t` は 64bit 以上の整数型と読み解けます。 ということで **C99 以後では** `(-262144)` は [プリプロセッサが処理する際には] `0xFFFFFFFFFFFC0000` に等しく `0x00000000FFFC0000` とは等しくない、ということになります。 `same` となったコンパイラは確かに [c99](/questions/tagged/c99 "'c99' のタグが付いた質問を表示") 非対応な古いものでした。 JIS X3014 というか ISO/IEC 14882 の新しい版では 16.1 に改正が入っているのでしょう(未確認)。この種の疑義を晴らすには新しい版を入手する必要がありそうです。 追記: `JIS X 3010-1993` (C89) を確認してみました。 `JIS X 3010-1993` 6.8.1 条件付き取込み > > `int` 及び `unsigned int` がそれぞれ `long` 及び `unsigned long` の表現をもつかのように動作する。 > > > C89 には 64bit 型をサポートしなければならない規定は無いはずなので、プリプロセッサ中の演算は(今回挙げた例では) 32bit で行われて結果は `same` になる、ということです。