375

使用時にコンパイラの最適化が行われることを読んだことがあります#pragma once。これにより、コンパイルが高速化されます。これは非標準であるため、クロスプラットフォームの互換性の問題が発生する可能性があることを認識しています。

これは、Windows 以外のプラットフォーム (gcc) 上のほとんどの最新のコンパイラでサポートされているものですか?

プラットフォームのコンパイルの問題を回避したいが、フォールバック ガードの余分な作業も回避したい:

#pragma once
#ifndef HEADER_H
#define HEADER_H

...

#endif // HEADER_H

私は心配する必要がありますか?これにさらに精神的なエネルギーを費やす必要がありますか?

4

15 に答える 15

360

#pragma onceには 1 つの欠点 (非標準であること以外) があり、同じファイルが異なる場所にある場合 (ビルド システムがファイルをコピーするため、これがあります)、コンパイラはこれらを異なるファイルと見なします。

于 2009-12-22T14:35:00.907 に答える
237

を使用すると、最新のコンパイラで動作するはずですが、標準のインクルード ガード#pragma onceを使用しない理由はありません。#ifndefそれはうまく動作します。1 つの注意点は、GCC がバージョン 3.4#pragma onceより前をサポートしていないことです。

また、少なくとも GCC では、標準の#ifndefインクルード ガードを認識して最適化するため、より遅くなることはありません#pragma once

于 2009-04-24T20:52:49.723 に答える
72

私は#pragma once(またはそのようなもの)が標準にあればいいのにと思います。インクルード ガードは大した問題ではありません (ただし、言語を学習している人々に説明するのは少し難しいようです) が、回避できたはずの小さな煩わしさのように思えます。

実際、99.98% の確率で、この動作は望ましい動作であるため、二重インクルードを許可する a または何かを使用#pragma onceして、ヘッダーの複数インクルードの防止がコンパイラーによって自動的に処理されていればよかったでしょう。#pragma

しかし、私たちは持っているものを持っています (あなたが持っていないかもしれないことを除いて#pragma once)。

于 2009-04-24T20:59:35.387 に答える
42

パフォーマンス上の利点についてはわかりませんが、確かに機能します。私はすべての C++ プロジェクトでこれを使用しています (MS コンパイラを使用していることを前提としています)。使うより効果的だと思います

#ifndef HEADERNAME_H
#define HEADERNAME_H
...
#endif

これは同じ仕事をし、プリプロセッサに追加のマクロを設定しません。

GCCはバージョン 3.4 で#pragma once公式にサポートしています。

于 2009-04-24T20:52:46.150 に答える
29

GCC は#pragma once3.4 以降をサポートしています。その他のコンパイラ サポートについては、 http://en.wikipedia.org/wiki/Pragma_onceを参照してください。

#pragma onceインクルードガードとは対照的に使用することの大きな利点は、コピー/貼り付けエラーを回避できることです。

私たちのほとんどは、新しいヘッダー ファイルをゼロから作成することはほとんどなく、既存のヘッダー ファイルをコピーして必要に応じて変更するだけです。#pragma onceインクルードガードの代わりに使用して作業テンプレートを作成する方がはるかに簡単です。テンプレートを変更する必要が少ないほど、エラーが発生する可能性が低くなります。異なるファイルで同じインクルード ガードを使用すると、奇妙なコンパイラ エラーが発生し、何が問題なのかを突き止めるのに時間がかかります。

TL;DR:#pragma onceの方が使いやすいです。

于 2013-08-28T12:41:19.250 に答える
12

私はそれを使用していますが、新しいヘッダーを作成するためにタイプする必要があるので、満足しています。Windows、Mac、Linux の 3 つのプラットフォームで問題なく動作しました。

パフォーマンスに関する情報はありませんが、#pragma とインクルード ガードの違いは、C++ 文法の解析の遅さに比べれば大したことではないと思います。それが本当の問題です。たとえば、同じ数のファイルと行を C# コンパイラでコンパイルしてみて、違いを確認してください。

結局、ガードやプラグマを使用しても問題はありません。

于 2009-04-25T13:32:36.013 に答える
11

' #pragma once' を使用しても何の効果もない可能性があります (どこでもサポートされているわけではありませんが、広くサポートされるようになっています)。とにかく条件付きコンパイル コードを使用する必要があります#pragma once。とにかく、コンパイラはおそらくそれを最適化します。ただし、ターゲット プラットフォームによって異なります。すべてのターゲットがそれをサポートしている場合は、先に進んで使用してください。ただし、プラグマのみを使用して、それをサポートしていないコンパイラに移植すると、すべてが崩壊するため、意識的な決定を行う必要があります。

于 2009-04-24T20:54:07.973 に答える
5

#pragma が一度読み取られると、ファイルを再度開く必要がないため、パフォーマンスが向上します。ガードを使用すると、コンパイラーはファイルを開いて、そのコンテンツを再度含めてはならないという情報を取得する必要があります (時間的にコストがかかる可能性があります)。

一部のコンパイラは、コンパイル単位ごとに、読み取りコードが含まれていないファイルを自動的に開かないため、これは単なる理論です。

とにかく、すべてのコンパイラに当てはまるわけではないので、理想的には #pragma once は、クロスプラットフォーム コードではまったく標準ではない/標準化された定義と効果がない場合は避ける必要があります。ただし、実際には、ガードよりも優れています。

最後に、この場合、各コンパイラの動作をチェックすることなく、コンパイラから確実に最高の速度を得ることができるより良い提案は、pragma once とガードの両方を使用することです。

#ifndef NR_TEST_H
#define NR_TEST_H
#pragma once

#include "Thing.h"

namespace MyApp
{
 // ...
}

#endif

そうすれば、両方を最大限に活用できます (クロスプラットフォームとコンパイル速度の向上)。

入力するのは時間がかかるので、私は個人的にツールを使用して、非常に気の利いた方法ですべてを生成するのを支援します (Visual Assist X)。

于 2009-04-24T21:04:31.287 に答える
4

常にではない。

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52566には、両方を含めることを意図した 2 つのファイルの良い例がありますが、タイムスタンプと内容が同一であるため (ファイル名が同一ではない)、誤って同一であると考えられていました。 .

于 2013-04-11T13:36:58.940 に答える
2

非常に大きなツリーで gcc 3.4 および 4.1 を使用して ( distccを使用する場合もあります)、標準のインクルード ガードの代わりに、または組み合わせて #pragma once を使用しても、速度が向上することはまだありません。

実際の節約がないため、古いバージョンのgccや他のコンパイラを混乱させる可能性があるという価値があるかどうかは本当にわかりません。私はさまざまなデリンターをすべて試したわけではありませんが、それらの多くを混乱させることは間違いありません.

私も早い段階で採用されていればよかったのですが、「ifndef が完全に機能しているのに、なぜそれが必要なのですか?」という議論が見られます。C の多くの暗いコーナーと複雑さを考えると、インクルード ガードは、最も簡単で自己説明的なものの 1 つです。プリプロセッサがどのように機能するかについて少しでも知識があれば、自明のはずです。

ただし、大幅なスピードアップが見られる場合は、質問を更新してください。

于 2009-04-25T01:56:24.160 に答える
2

msvc または Qt (Qt 4.5 まで) を使用する場合、GCC (3.4 まで) と msvc の両方が をサポートしている#pragma onceため、 を使用しない理由はわかりません#pragma once

ソースファイル名は通常同じクラス名であり、クラス名の名前を変更するためにリファクタリングが必要になる場合があり、その後も変更する必要があることがわかっているため、手動で維持することは賢明な作業ではない#include XXXXと思います。#include xxxxxVisual Assist X 拡張機能を使用しても、「xxxx」を維持する必要はありません。

于 2013-09-14T12:39:08.413 に答える
2

主な違いは、インクルード ガードを読み取るためにコンパイラがヘッダー ファイルを開く必要があることです。対照的に、pragma は、コンパイラがファイルを追跡し、同じファイルの別のインクルードに遭遇したときにファイル IO を実行しないようにします。それは取るに足らないことのように聞こえるかもしれませんが、大規模なプロジェクト、特に適切なヘッダーのないプロジェクトには分野が含まれるため、簡単にスケールアップできます。

とはいえ、最近のコンパイラ (GCC を含む) は、インクルード ガードを pragma once のように扱うほどスマートです。つまり、ファイルを開かず、ファイル IO ペナルティを回避します。

プラグマをサポートしていないコンパイラでは、少し面倒な手動実装を見てきました..

#ifdef FOO_H
#include "foo.h"
#endif

私は個人的に #pragma once アプローチが好きです。名前の競合や潜在的なタイプミスの煩わしさを回避できるからです。比較すると、よりエレガントなコードでもあります。とはいえ、移植可能なコードの場合、コンパイラが文句を言わない限り、両方を持っていても害はありません。

于 2011-12-17T12:52:52.437 に答える
2

今日、昔ながらのインクルード ガードは #pragma once と同じくらい高速です。コンパイラがそれらを特別に処理しなくても、#ifndef WHATEVER が検出され、WHATEVER が定義されている場合は停止します。今日、ファイルを開くのは非常に安価です。改善したとしてもミリ秒単位です。

#pragma once は何の役にも立たないので、単純に使用しません。他のインクルード ガードとの衝突を避けるために、次のようなものを使用します。 CI_APP_MODULE_FILE_H --> CI = Company Initials; APP = アプリケーション名。残りは自明です。

于 2010-03-04T04:39:26.133 に答える