23

#pragma onceいつでも機能する必要性を私は理解していません#ifndef #define #endif

他のファイルとリンクするための使用法を見てきました#pragma commentが、コンパイラ設定のセットアップはIDEを使用した方が簡単でした。

それの他のいくつかの使用法#pragmaは有用ですが、広く知られていませんか?

編集:

#pragmaディレクティブのリストの直後ではありません。おそらく、この質問をもう少し言い換える必要があります。

一緒に書いたコードは#pragmaどれが役に立ちましたか?

一目で答え:

回答および/またはコメントしてくれたすべての人に感謝します。これが私が有用だと思ったいくつかの入力の要約です:

  • Jasonは、大規模システムでのコンパイルを高速化すること#pragma onceを提案しました。#ifndef #define #endifスティーブは飛び込んでこれをサポートしました。
  • 280Z28は一歩進んで、MSVCに適していると述べました#pragma onceが、GCCコンパイラはに最適化されてい#ifndef #define #endifます。したがって、両方ではなく、どちらかを使用する必要があります。
  • Jason#pragma packはバイナリ互換性についても言及しましたが、移植性とエンディアンの問題が発生する可能性があるため、Cliffordはこれに反対しています。Evanはサンプルコードを提供し、Dennisは、ほとんどのコンパイラが整列のためにパディングを強制することを通知しました。
  • sblomは#pragma warning、実際の問題を切り分け、すでに確認されている警告を無効にするために使用することを提案しました。
  • Evanは#pragma comment(lib, header)、IDEを再設定せずに、プロジェクト間で簡単に移植できるようにすることを提案しました。もちろん、これはあまり移植性がありません。
  • sbiは、#pragma messageVCユーザーが行番号情報を含むメッセージを出力するための優れたトリックを提供しました。Jamesはさらに一歩進んで、MSVCのメッセージを許可errorまたは照合し、エラーリストなどの適切なメッセージを表示します。warning
  • Chrisは#pragma region、MSVCでカスタムメッセージを使用してコードを折りたたむことができるように提供しました。

おっと、待って、必要な場合を除いて#pragmasを使用しないことについて投稿したい場合はどうすればよいですか?

  • クリフォードは、使用しないことについて別の観点から投稿しました#pragma。称賛。

SOersが回答を投稿したいという衝動を感じたら、このリストにさらに追加します。みんな、ありがとう!

4

8 に答える 8

12

すべてのプラグマには用途があります。そうでない場合、そもそもプラグマはありません。

pragma "once"は、コードを別のコンパイラに移植しないことがわかっている場合は、入力が少なくてすっきりしています。コンパイラはヘッダーを解析してその内容を含めるかどうかを判断する必要がないため、より効率的である必要があります。

編集:コメントに答えるには:200kBのヘッダーファイルがあると想像してください。「once」を使用すると、コンパイラーはこれを1回ロードし、次にヘッダーが参照されていることを確認するときに、ヘッダーを含める必要がないことを認識します。#ifを使用すると、毎回ファイル全体をロードして解析し、ifによってすべてのコードが無効になっていることを確認する必要があります。これは、ifを毎回評価する必要があるためです。大規模なコードベースでは、これは大きな違いを生む可能性がありますが、実際には(特にプリコンパイル済みヘッダーの場合)そうではない場合があります。

プラグマ「pack」は、構造体のバイナリ互換性が必要な場合に非常に役立ちます。

編集:バイナリ形式の場合、指定するバイトは必要な形式と正確に一致する必要があります。コンパイラがパディングを追加すると、データアライメントが台無しになり、データが破損します。したがって、OS呼び出しまたはTCPパケットとの間で受け渡しするバイナリファイル形式またはメモリ内構造へのシリアル化では、バイナリ形式に直接マップする構造体を使用する方が、「メンバーごとのシリアル化」よりもはるかに効率的です(フィールドを1つずつ書き込む)-使用するコードが少なく、実行速度がはるかに速くなります(今日でも組み込みアプリケーションでは不可欠です)。

プラグマ「エラー」と「メッセージ」は、特に条件付きコンパイルブロック内で非常に便利です(例:「エラー:「ePhoneのリリース」ビルドは実装されていません」、メッセージ:「このビルドでは追加のデバッグおよびプロファイリングコードが有効になっています」)

プラグマ「警告」(特にプッシュ&ポップを使用)は、特に警告レベル4でビルドする場合は特に、記述が不十分なサードパーティのヘッダー(警告でいっぱい)を含める場合に、迷惑な警告を一時的に無効にするのに非常に役立ちます。

編集:警告が発生したときに気づき、すぐに修正できるように、ビルドで警告をゼロにすることをお勧めします。もちろん、独自のコードですべての警告を修正する必要があります。ただし、一部の警告は単に修正できず、重要なことは何も教えてくれません。さらに、警告を修正するためにコードを変更できないサードパーティのライブラリを使用している場合は、ライブラリの警告を無効にすることで、ビルドから「スパム」を削除できます。push / popを使用すると、ライブラリのインクルード中にのみ警告を選択的に無効にできるため、独自のコードがコンパイラによってチェックされます。

于 2010-04-24T07:56:15.837 に答える
9

おっしゃるように、リンク時に特定のライブラリにリンクするように指示するVisualC++のプラグマを見てきました。winsockライブラリが必要なライブラリに便利です。このように、プロジェクトをリンクするためにプロジェクト設定を変更する必要はありません。例: #pragma comment(lib,"wsock32.lib")。.libを必要とするコードが関連付けられているので、これが気に入っています。さらに、それをファイルに入れると、そのコードを別のプロジェクトで再利用する場合に忘れることはできません。

また、データ構造をパッキングするためのプラグマは、データメンバーのオフセットが重要となるシステムやネットワークプログラミングで特に有用であることがよくあります。元:

#pragma pack(push, 1) // packing is now 1
struct T {
char a;
int b;
};
#pragma pack(pop) // packing is back to what it was

// sizeof(T) == sizeof(char) + sizeof(int), normally there would be padding between a and b
于 2010-04-24T07:30:20.743 に答える
9

可能な限り、#pragmaは避けてください。#pragmaコンパイラ指令は常にコンパイラ固有であるため、移植性はありません。それらは最後の手段と見なされるべきです。

さらに、認識されないプラグマに遭遇したコンパイラにISOが要求する動作は、単にそれを無視することです。これは警告なしにサイレントに実行される可能性があるため、ディレクティブがコードの正しい動作に不可欠である場合、別のコンパイラでコンパイルすると、コンパイルされても期待どおりに実行されない可能性があります。たとえば、GCCはごくわずかなプラグマを使用し、主にターゲット固有のコンパイラの動作または他のコンパイラとの互換性のためにのみ使用します。したがって、移植性を確保したい場合は、次のような構成になります。

#if _MSC_VER
  #pragma PACK(push,1)
#elif   __GNUC__
  // nothing to do here
#else
  #error "Unsupported compiler"
#endif
  struct sPackedExample
  {
      // Packed structure members
#if _MSC_VER
  } ;                              // End of MSVC++ pragma packed structure
  #pragma pack (pop)
#elif   __GNUC__
  }__attribute__((__packed__)) ;   // End of GNU attribute packed structure
#endif

これは混乱であり、ツリーの木材がすぐに見えなくなり、コンパイラのサポートを追加すると問題が悪化します(コンパイラを識別する事前定義されたマクロの知識が必要になります)。

[注:] GCC 4.xは実際にはMS互換性のために#pragmaパックをサポートしているため、上記の例は多少工夫されていますが、これはまだ使用されている可能性のある以前のバージョンのGCCや他のコンパイラには当てはまりません。

'#pragma once'は特に問題があります。これは、それをサポートしていないコンパイラの場合、前処理すると、最も些細な場合を除いて、コードが破損するためです。より冗長でありながら移植性の高いソリューションをお勧めします。Visual C ++のアプリケーションとコード生成の「ウィザード」がそれを使用する場合がありますが、そのようなコードはどのような場合でも移植性がないことがよくあります。このようなコードを使用するときは、基本的にプロジェクトをMicrosoftのツールにロックしていることに注意する必要があります。これは問題ではないかもしれませんが、独自のコードでディレクティブを使用することはお勧めしません。

元の質問に対処するには:「#pragmaを使用してどのコードを記述しましたか?」; おそらくプラグマを回避するための便利な方法を検討する必要がありますか?

それはおそらく「有用性」の問題ではなく、「必要性」の問題であるべきです。たとえば、私が使用した多くの組み込みシステムコンパイラでは、#pragmaディレクティブを使用して、関数が割り込みサービスルーチンであり、したがって、異なる開始/終了コードを持ち、多くの場合、異なるスタックで動作することを指定します。このようなプラグマを回避するには、ターゲットのアセンブラ言語の知識が必要であり、割り込みを処理するためにCコードが呼び出されると効率が低下します。

于 2010-04-24T08:33:15.400 に答える
8

これはsbiの答えと非常に似ていますが、いくつかの追加機能があります。

私は#pragma messageしばらくの間、Microsoft VisualC++で次のマクロのセットを使用しました。

#define EMIT_COMPILER_WARNING_STRINGIFY0(x) #x
#define EMIT_COMPILER_WARNING_STRINGIFY1(x) EMIT_COMPILER_WARNING_STRINGIFY0(x)
#define EMIT_COMPILER_MESSAGE_PREFACE(type) \
    __FILE__ "(" EMIT_COMPILER_WARNING_STRINGIFY1(__LINE__) "): " type ": "

#define EMIT_COMPILER_MESSAGE EMIT_COMPILER_MESSAGE_PREFACE("message")
#define EMIT_COMPILER_WARNING EMIT_COMPILER_MESSAGE_PREFACE("warning")
#define EMIT_COMPILER_ERROR   EMIT_COMPILER_MESSAGE_PREFACE("error")

使用されます:

#pragma message(EMIT_COMPILER_WARNING "This code sucks; come back and fix it")

これにより、ビルド出力に次のテキストが表示されます。

1>z:\sandbox\test.cpp(163): warning : This code sucks; come back and fix it

出力はVisualC++エラーメッセージ形式と一致するため、エラー、警告、およびメッセージは、他のすべてのコンパイラの警告およびエラーとともにエラーリストに表示されます。

「警告」マクロは、コード内の単純なマクロよりもはるかに不快であり、// todo fix this戻ってきて何かを修正することを忘れないようにするのに役立ちます。

#error「エラー」マクロは、コンパイルを失敗させますが、ディレクティブのようにコンパイルプロセスをすぐには停止しないため便利です。

于 2010-04-25T00:26:42.737 に答える
4

VCでは、過去にこれを使用しました。

#define STRINGIFY( L )       #L
#define MAKESTRING( M, L )   M(L)
#define SHOWORIGIN           __FILE__ "("MAKESTRING( STRINGIFY, __LINE__) "): "

// then, later...

#pragma message( SHOWORIGIN "we need to look at this code" )
// ...
#pragma message( SHOWORIGIN "and at this, too" )

出力:

c:\ ... \ test.cpp(8):このコードを確認する必要があります
c:\ ... \ test.cpp(10):そしてこれも

出力ペインでそれをダブルクリックすると、IDEが適切なファイルと行に移動します。

于 2010-04-24T12:17:53.720 に答える
4

Visual Studioでは、C++プリプロセッサもサポートしています

#pragma region Some Message Goes Here
...
#pragma endregion

次に、コードエディタでこの領域を折りたたんで、上記のメッセージのみが表示されるようにします。これは、C#リージョンの構文に類似しています。

于 2010-04-24T18:06:55.060 に答える
3

#pragma定義上、プラットフォーム固有のコンパイラ/プリプロセッサディレクティブ用です。ここでMSVC++#pragmasについて話しているようです。あなたは彼らの完全なリスト、またはgccの完全なリストを見つけることができます。

他のコンパイラは完全に異なるリストを持っています。

ただし、MSVC ++に戻ると、私のお気に入りのプラグマの1つはです#pragma warning。私は通常、「警告をエラーとして扱う」を有効にしてコードを作成し、問題を引き起こしていないことを確認するために確認した特定の警告を外科的に無効にします。これにより、コンパイラーはビルド中にさらに多くの問題を検出するのに役立ちます。

于 2010-04-24T06:57:41.007 に答える
0
#pragma comment(lib, "WS2_32.lib")

winsockライブラリを使用するプロジェクトの場合

于 2010-04-24T12:57:31.077 に答える