0

複数インクルードの最適化が gcc でどのように機能するかを理解しようとしています。最近、標準ヘッダー ファイルのガードを含む多くのコードを読んでいます。

#ifndef _STDIO_H_
#include <stdio.h>
#endif 

そして、この構造に利点があるかどうかを調べようとしています。

これをもう少しよく理解するために私が書いた例を次に示します。

header1.h

#ifndef _HDR_H_
#define _HDR_H_

#define A    (32)

#endif

header2.h

#ifndef _HDR_H_
#define _HDR_H_

#define A    (64)

#endif

hdr.c

#include <stdio.h>
#include "header1.h"
#include "header2.h"

int main()
{
     printf("%d\n", A);
     return 0;
}

と の両方が同じインクルード ガードheader1.hを使用していることに注意してください。header2.h予想どおり、このプログラムAは header1.h で定義された値を出力します。header2.h は、同じインクルード ガードを使用するためスキップされます。

これが私が理解しようとしているものです

  • header2.h を解析するときに、プリプロセッサがこのファイルをスキップするのはどの時点ですか? 私の理解では、このファイルは 1 行目のディレクティブの直後にスキップされます#if。つまり、一致するのを待つ必要はありません#endif。これは正しいです?
  • これがどのように機能するかを示すために、上記の例に何を追加できますか?

編集:答えてくれてありがとう。これは今、より理にかなっています。フォローアップの質問です。この投稿の最初の行にリンクされているページには、次のテキストがあります

プリプロセッサはそのようなヘッダー ファイルを認識するため、ヘッダー ファイルが後続の #include ディレクティブに表示され、FOO が定義されている場合、それは無視され、ファイルを前処理したり、再度開いたりすることはありません。これは、複数インクルードの最適化と呼ばれます。

私がこれを正しく理解している場合、これは、特定のコンパイル プロセスに複数回含まれていても、ヘッダー ファイルは 1 回だけ読み取られることを意味します。そのため、アプリケーション コードまたはヘッダー ファイルにインクルード ガードを追加しても、何のメリットもありません。

4

5 に答える 5

2

プリプロセッサは、false#if[[n]def]に続くすべての入力のブロックを開始して、後続のコンパイラ ステップを通過します。

ただし、プリプロセッサは入力の読み取りを続行し、すべての条件付きコンパイル ディレクティブのネストの深さを追跡します#

入力のブロックを開始した場所の一致する が見つかると、#endif単にブロックを停止します。

于 2013-12-20T13:55:30.437 に答える
2

header2.h を解析するときに、プリプロセッサがこのファイルをスキップするのはどの時点ですか?

ファイルはスキップされません。

私の理解では、1 行目の #if ディレクティブの直後にこのファイルをスキップします。つまり、一致する #endif を待つ必要はありません。これは正しいです?

はい、いいえ。一部のコンパイラは、最初のヘッダー ファイルを解析するときに、sentry マクロを識別し、2 番目のファイルで見つかった場合、すぐに解析を停止します。他のコンパイラはヘッダーを再度解析します (一致する を探し#endifます)。

これがどのように機能するかを示すために、上記の例に何を追加できますか?

セントリー マクロの内側と外側に印刷メッセージを追加する

#ifdef   _HEADER_INCLUDED
#define  _HEADER_INCLUDED
...
#pragma message ("inside sentry in " __FILE__ "\n")
#endif //#ifdef   _HEADER_INCLUDED

#pragma message ("outside sentry in " __FILE__ "\n")

関連資料:

  • #pragma onceセントリー マクロの代わりに使用できます。ファイルがほとんど解析されないため、コンパイルが高速になります。マクロ名が衝突する心配はありません。
  • ヘッダー ファイルが再度読み込まれないように、インクルードの if チェックを sentry マクロにラップすることができます。これは通常、複数のヘッダーを何度も含むライブラリ ヘッダーで使用されます。醜いコードを犠牲にして、コンパイルを大幅に高速化できます。

    #ifndef __LIST_H_

    #include "list.h"

    #endif

于 2013-12-20T14:13:36.937 に答える
2

プリプロセッサは header2.h をスキップしません。常にそれが含まれ、展開すると#ifndefブロック内のものは無視されます。

あなたの例では、herader2.h に決して到達しないためA、32 になります。到達した場合、「A」に#define複数の があるため、ある種の「マクロ再定義エラー」が発生します。#defineこれを修正するには、#undefA.

最近では、ヘッダー ファイルにインクルード ガードを記述する手間を省くために、ほとんどのコンパイラがこの#pragma onceディレクティブをサポートしています。

于 2013-12-20T13:48:43.747 に答える