1. ホーム
  2. c

[解決済み] Cプリプロセッサはなぜ "linux "という単語を定数 "1 "と解釈するのですか?

2022-03-21 09:11:11

質問

なぜ C のプリプロセッサーは GCC という単語を解釈します。 linux (小文字)を定数 1 ?

test.c:

#include <stdio.h>
int main(void)
{       
    int linux = 5;
    return 0;
}

結果 $ gcc -E test.c (前処理段階で停止)。

....
int main(void)
{
    int 1 = 5;
    return 0;
}

もちろんエラーになります。

(ちなみに #define linux の中に stdio.h ファイルを作成します)。

解決方法は?

昔は(ANSI以前)、以下のような記号をあらかじめ定義していました。 unixvax は、コンパイル時にコードがどのシステム用にコンパイルされているかを検出できるようにする方法でした。当時は公式の言語標準がなく(K&Rの初版の巻末にある参考資料以上)、C言語のコードは複雑な迷路のようなものでした。 #ifdef のように、システム間の差異を許容するためのものです。これらのマクロ定義は、一般にライブラリのヘッダーファイルで定義されるのではなく、コンパイラ自身が設定するものであった。どの識別子を実装で使って、どれをプログラマが使うかといったルールがないため、コンパイラは自由に unix プログラマーはそのような名前を自分の目的のために使わないようにすればいいと思っていた。

1989年のANSI C規格では、実装が合法的に事前定義できるシンボルを制限するルールが導入されました。コンパイラが定義するマクロは、アンダースコア2つで始まる名前か、アンダースコアの後に大文字が続く名前に限られ、プログラマはそのパターンに合致しない識別子や標準ライブラリで使われていない識別子を自由に使用することができるようになった。

その結果、コンパイラに予め定義された unix または linux のようなものを使用する完全に合法的なコードはコンパイルに失敗するため、不適合です。 int linux = 5; .

たまたま、gccはデフォルトでは非適合ですが、正しいコマンドラインオプションで適合させることができます(適度に)。

gcc -std=c90 -pedantic ... # or -std=c89 or -ansi
gcc -std=c99 -pedantic
gcc -std=c11 -pedantic

参照 gccマニュアル をご覧ください。

gcc は将来のリリースでこれらの定義を段階的に縮小していくので、これらに依存するコードを書くべきではありません。もしあなたのプログラムがLinuxターゲット用にコンパイルされているかどうかを知る必要がある場合、そのプログラムは __linux__ が定義されています (gccまたはそれと互換性のあるコンパイラを使っていることが前提です)。参照 GNU Cプリプロセッサー・マニュアル をご覧ください。

全く関係ない余談ですが、1987年の「ベストワン・ライナー」の受賞者は 国際難読化Cコードコンテスト David Korn (そう、Korn Shell の作者) は、定義済みの unix マクロを使用しています。

main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}

印刷されます "unix" しかし、その理由はマクロ名のスペルとは全く関係ありません。