0

ファイルをインクルードする無限ループが原因でコンパイラの問題が発生するのか、それともリンカの問題が発生するのか疑問に思っています。私はこれを試しました:

/* file : try.c */
#include "try1.c"
int main(void) {}

/* file : try1.c */
#include "try.c"
int a(void) { return 0; }

コンパイルするコマンドは次のとおりです。

gcc -Wall try.c -o try

これは明らかに非常に長い出力を引き起こします(次のように始まります):

try.c:5:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
In file included from try.c:1:0,
                 from try1.c:1,
                 from try.c:1:
try1.c:4:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
In file included from try1.c:1:0,
                 from try.c:1:
try.c:5:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
In file included from try.c:1:0:
try1.c:4:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
try.c:5:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
In file included from try.c:2:0,
                 from try1.c:1,
                 from try.c:1,
                 from try1.c:1,
                 from try.c:1,
                 from try1.c:1,
                 from try.c:1,
                 from try1.c:1,
                 from try.c:1,
                 from try1.c:1,
                   .
                   .
                   etc...

まあ、明らかにここには無限ループがあります。しかし、いつ発生しますか?コンパイルプロセスまたはリンカープロセスで?ここで同じ名前の複数の関数を定義するため(ループのため)、コンパイルプロセスで教えてくれると思いますが、リンカープロセスでファイルを結合する部分ではありません(そして、 1 つのファイルのみの場合、コンパイルに問題はありません) ?

ありがとう !

4

4 に答える 4

5

実際、#include- 型ステートメントの展開は「前処理」ステップと呼ばれます。以前は、これらのステップはすべて「コンパイル」が発生する前に個別のステップとして処理されると考えていましたが、@EricPostpischil はコメントで指摘し (そしてそれを示す例を示しました)、前処理とコンパイルの 2 つが発生しているように見えます。同時に (ソース ファイルの行の順序に従って)。つまり、#コマンド (「プリプロセッサ ディレクティブ」) の展開は、「コンパイルが行われるときに」行われます。その意味で、エラーは「コンパイル」エラーです。しかし、私の考えでは、「#include「プリプロセッサステップ」がコンパイラによって処理されると、線がぼやけます。問題を引き起こしているのは間違いなくリンカではありません-コンパイラは、そのステップに到達するずっと前にあきらめます.

#include一般的なコメントとして、あるファイルを別のファイルにするのは良い習慣ではありません.c- これはリンカが使用されるべきものです。また、「再帰的なインクルード」を防ぐために.h、コンパイラに付属のファイルに次のような構造がよく見られます。

#ifndef __MYINCLUDEFILE
#define __MYINCLUDEFILE
... put the body of the include file here
#endif

これにより、複数の場所から呼び出された場合でも、インクルード ファイルが 1 回だけインクルードされることが保証されます (最初にインクルードされるときは__MYINCLUDEFILE変数が定義され、次にインクルードされるときは関数の本体全体がスキップされます)。すべてのインクルード ファイルでこれを行うと、陥ったような「再帰トラップ」は発生しなくなります。

@wildplasser が指摘したように、 and の使用は_NAME言語__NAMEと実装のために予約されています。コンパイラに同梱されているヘッダー ファイルにこのような構造が表示されるため、例として使用しています。独自の .h ファイルを作成するときは、一意の識別子を作成する別の規則を考える必要があります。

于 2013-08-09T14:11:03.427 に答える
2

コードが変更されるさまざまな段階があります。

インクルードは前処理段階で展開されます。したがって、無限ループを作成しようとすると、実際には、コンパイルまたはリンクが発生する前の前処理段階でのみエラーになります。

于 2013-08-09T14:16:59.040 に答える
2

すでに失敗しているのは前処理です。実証するために、ソースを次のように前処理します。

gcc -E try.c

そしてそれが失敗するのを見てください。

于 2013-08-09T14:24:01.567 に答える
2

「#」で始まるすべての「もの」は、プリプロセッサによって処理されます。そのため、インクルード ガードも "#" で始まります。同時に処理する必要があります。

于 2013-08-09T14:19:02.050 に答える