コンパイラーがヘッダーファイルを2回インポートすることを避けられないのはなぜですか?


13

C ++の新機能!だから私はこれを読んでいた:http : //www.learncpp.com/cpp-tutorial/110-a-first-look-at-the-preprocessor/

ヘッダーガード

ヘッダーファイルには他のヘッダーファイルを含めることができるため、ヘッダーファイルが複数回インクルードされる状況になる可能性があります。

そこで、これを回避するためにプリプロセッサディレクティブを作成します。しかし、私はわからない-なぜコンパイラがちょうどできないのか... 同じものを2回インポートしないのですか?

ヘッダーガードはオプションです(ただし、明らかに良い方法です)ので、何かを2回インポートしたいというシナリオがあると思います。そのようなシナリオはまったく考えられませんが。何か案は?


MSコンパイラには#pragma once、そのファイルを1回だけ含めるようにコンパイラに指示するものがあります。
CodesInChaos

回答:


27

新しい言語で示されているように、それらは可能です。

しかし、設計の決定は何年も前に行われ(Cコンパイラが複数の独立した段階だったとき)、互換性を維持するために、プリプロセッサは特定の方法で動作し、古いコードが期待どおりにコンパイルされるようにする必要があります。

C ++はヘッダーファイルをCから処理する方法を継承するため、同じ手法を維持していました。古いデザインの決定をサポートしています。しかし、動作方法を変更すると、多くのコードが破損する可能性があるため、非常に危険です。そのため、言語の新規ユーザーにインクルードガードの使用方法を教える必要があります。

意図的に複数回インクルードする場合、ヘッダーファイルにはいくつかのトリックがあります(これは実際に便利な機能を提供します)。ただし、パラダイムをゼロから再設計すると、ファイルをインクルードするデフォルト以外の方法にすることができます。


7

そうでなければ、Cとの互換性を維持し、したがって従来のパッキングシステムではなくプリプロセッサを使い続けることを選択したことを考えると、それほど表情豊かではありません。

私に思い浮かぶことの1つは、APIであるプロジェクトがあったことです。2つのヘッダーファイルx86lib.hx86lib_internal.h。内部は巨大だったので、ユーザーがコンパイルのために余分な時間を確保する必要がないように、「パブリック」ビットをx86lib.hに分離しました。

これにより依存関係に関する面白い問題が発生したため、x86lib_internalでこのようなフローが発生しました

  1. 内部プリプロセッサ定義を設定します
  2. x86lib.hをインクルードします(内部が定義されたときに特定の動作をするのが賢明でした)
  3. 何かをして、x86lib.hで使用されるものを紹介します
  4. プリプロセッサ定義後に設定
  5. x86lib.hを再度インクルードします(今回は、x86lib_internalの要素に依存する分離されたAFTER部分を除くすべてを無視します

最善の方法だとは言いませんが、私が望んでいたものを達成しました。


0

重複ヘッダーの自動除外の難しさの1つは、ファイル名を含むことの意味に関して、C標準が比較的静かであることです。たとえば、コンパイル中のメインファイルにディレクティブ#include "f1.h"とが含ま#include "f2.h"れ、それらのディレクティブで見つかったファイルに両方が含まれているとします#include "f3.h"f1.hおよびf2.hが異なるディレクトリにあるが、インクルードパスを検索して見つかった場合、#includeそれらのファイル内のディレクティブが同じf3.hファイルまたは異なるファイルをロードすることを意図していたかどうかは不明です。

相対パスを含むインクルードファイルの可能性を追加すると、事態はさらに悪化します。ヘッダーファイルがネストされたincludeディレクティブに相対パスを使用し、提供されたヘッダーファイルに変更を加えないようにする場合、プロジェクトのディレクトリ構造内の複数の場所にヘッダーファイルを複製する必要がある場合があります。そのヘッダーファイルの複数の物理コピーが存在していても、それらは意味的には単一のファイルであると見なされる必要があります。

場合#pragma onceディレクティブがフォローする識別子許可once識別子は、以前の遭遇から1一致した場合、コンパイラは、ファイルをスキップする必要があることを意味論で、#pragma onceディレクティブを、その意味は明確なことでしょう。#includeディレクティブが#pragma once以前のタグと同じタグ付きファイルをロードすることを伝えることができるコンパイラーは、ファイルを再度開かずにスキップすることで少し時間を節約できますが、ファイルはスキップされるため、そのような検出は意味的に重要ではありませんファイル名が一致として認識されたかどうか。ただし、そのように動作するコンパイラは知りません。ファイルがパターンに一致するかどうかをコンパイラに観察#ifndef someIdentifier / #define someIdentifier / #endif [for that ifndef] / nothing followingさせ、次の#pragma once someIdentifier場合にそのようなものを上記と同等に処理するsomeIdentifier 定義されたままで、基本的には良好です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.