GNU/Linux >> Linux の 問題 >  >> Linux

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

これは (文書化されていない) 「GNU 拡張機能」のようです:[訂正 :やっとドキュメントに言及が見つかりました。以下を参照してください。]

次のコマンドは -dM を使用しています すべてのプリプロセッサ定義を出力するオプション。入力「ファイル」は空であるため、事前定義されたマクロが正確に表示されます。標準のubuntuインストールでgcc-4.7.3で実行されました。プリプロセッサが標準対応であることがわかります。合計で、-std=gnu99 の 243 個のマクロがあります -std=c99 で 240;関連性のために出力をフィルタリングしました。

$ cpp --std=c89 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1

$ cpp --std=gnu89 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1

$ cpp --std=c99 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1

$ cpp --std=gnu99 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1

「gnu 標準」バージョンも #define unix . (c11 を使用 および gnu11 同じ結果が得られます。)

彼らには理由があると思いますが、gcc のデフォルトのインストールを行うように思えます (これは C コードを -std=gnu89 でコンパイルします)。 特に明記しない限り) 不適合、そして -- この質問のように -- 驚くべきことです。名前がアンダースコアで始まらないマクロでグローバル名前空間を汚染することは、準拠した実装では許可されていません。 (6.8.10p2:「他の定義済みマクロ名は、先頭のアンダースコアで始まり、大文字または 2 番目のアンダースコアが続くものとする」が、付録 J.5 (移植性の問題) で述べたように、そのような名前はしばしば定義済みです。)

私が最初にこの回答を書いたとき、この問題に関するドキュメントをgccで見つけることができませんでしたが、C実装定義の動作でもC拡張でもなく、 cpp マニュアルのセクション 3.7.3 には、次のように記載されています:

<ブロック引用>

予約済みの名前空間の外にあるすべての定義済みマクロを段階的に廃止しています。新しいプログラムでは絶対に使用しないでください…


昔 (ANSI 以前) では、unix などのシンボルを事前に定義していました。 そして vax コンパイル時にどのシステム用にコンパイルされているかをコードが検出できるようにする方法でした。当時は (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 プリプロセッサのマニュアルを参照してください。

あまり関係のないことですが、David Korn (そうです、Korn Shell の作成者) による 1987 年の International Obfuscated C Code Contest の「ベスト ワン ライナー」受賞者は、事前定義された unix を利用しました。 マクロ:

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

"unix" を出力します 、しかし、マクロ名のスペルとはまったく関係のない理由により.


Linux
  1. MacからLinuxに切り替えた理由

  2. 私のLinuxストーリー:なぜ人々にRaspberryPiを紹介するのか

  3. ルートユーザーがSudo権限を必要とするのはなぜですか?

  1. Linux –ルートディレクトリがA /記号で示されているのはなぜですか?

  2. Linux –Setuidが機能しないのはなぜですか??

  3. Linux –カーネルがInitを実行できないのはなぜですか?

  1. Linux dm-multipath で Lun World Wide ID が数字の 3 で始まる理由

  2. 「ls」コマンドは Linux/Unix でどのように機能しますか?

  3. Bash(Linux シェル)で Ctrl + V が貼り付けられないのはなぜですか?