167

私のコードが使用していると思われる Boost のバージョンを把握しようとしています。私はこのようなことをしたい:

#error BOOST_VERSION

ただし、プリプロセッサは BOOST_VERSION を展開しません。

実行時にプログラムから出力できることはわかっていますし、プリプロセッサの出力を見て答えを見つけられることもわかっています。コンパイル中にこれを行う方法があると便利だと思います。

4

14 に答える 14

180

これは元のクエリからかなり時間が経っていることはわかっていますが、これはまだ役立つ可能性があります。

これは、文字列化演算子「#」を使用して GCC で実行できますが、2 つの段階が必要です。

#define XSTR(x) STR(x)
#define STR(x) #x

マクロの値は、次のように表示できます。

#pragma message "The value of ABC: " XSTR(ABC)

参照: gcc オンライン ドキュメントの 3.4 文字列化。

使い方:

プリプロセッサは引用符で囲まれた文字列を理解し、通常のテキストとは異なる方法で処理します。文字列の連結は、この特別な処理の一例です。メッセージ プラグマには、引用符で囲まれた文字列の引数が必要です。引数に複数のコンポーネントがある場合、文字列連結を適用できるように、それらはすべて文字列でなければなりません。プリプロセッサは、引用符で囲まれていない文字列が引用符で囲まれているかのように扱われるべきであると想定することはできません。もしそうなら:

#define ABC 123
int n = ABC;

コンパイルしません。

今考えてみましょう:

#define ABC abc
#pragma message "The value of ABC is: " ABC

これはと同等です

#pragma message "The value of ABC is: " abc

abc (引用符なし) は前の文字列と連結できないため、これによりプリプロセッサ警告が発生します。

ここで、プリプロセッサの stringize について考えてみましょう (以前は stringification と呼ばれていましたが、ドキュメント内のリンクは、改訂された用語を反映するように変更されています。(ちなみに、どちらの用語も同じように嫌われています。正しい用語は、もちろん stringifaction です。更新する準備をしてください)。あなたのリンク。)) 演算子。これはマクロの引数にのみ作用し、展開されていない引数を二重引用符で囲まれた引数に置き換えます。したがって:

#define STR(x) #x
char *s1 = "abc";
char *s2 = STR(abc);

s1 と s2 に同じ値を割り当てます。gcc -E を実行すると、出力でこれを確認できます。おそらく、STR は ENQUOTE のような名前を付けたほうがよいでしょう。

これにより、引用符で囲まれていない項目を引用符で囲む問題が解決されます。現在の問題は、引数がマクロの場合、マクロが展開されないことです。これが、2 番目のマクロが必要な理由です。XSTR はその引数を展開し、STR を呼び出して、展開された値を引用符で囲みます。

于 2012-05-29T00:41:38.957 に答える
127

BOOST_PP_STRINGIZEC++ では優れたソリューションのようですが、通常の C ではそうではありません。

GNU CPPの私のソリューションは次のとおりです。

/* Some test definition here */
#define DEFINED_BUT_NO_VALUE
#define DEFINED_INT 3
#define DEFINED_STR "ABC"

/* definition to expand macro then apply to pragma message */
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define VAR_NAME_VALUE(var) #var "="  VALUE(var)

/* Some example here */
#pragma message(VAR_NAME_VALUE(NOT_DEFINED))
#pragma message(VAR_NAME_VALUE(DEFINED_BUT_NO_VALUE))
#pragma message(VAR_NAME_VALUE(DEFINED_INT))
#pragma message(VAR_NAME_VALUE(DEFINED_STR))

上記の定義により、次の結果が得られます。

test.c:10:9: note: #pragma message: NOT_DEFINED=NOT_DEFINED
test.c:11:9: note: #pragma message: DEFINED_BUT_NO_VALUE=
test.c:12:9: note: #pragma message: DEFINED_INT=3
test.c:13:9: note: #pragma message: DEFINED_STR="ABC"

"defined as interger ""defined as string"、および"defined but no value"変数の場合、それらは正常に機能します。「定義されていない」変数のみ、元の変数名とまったく同じように表示されました。あなたはそれに慣れる必要があります-または、誰かがより良い解決策を提供できるかもしれません.

于 2012-04-19T11:29:58.317 に答える
61

Visual C ++を使用している場合は、次を使用できます#pragma message

#include <boost/preprocessor/stringize.hpp>
#pragma message("BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION))

編集:リンクを提供してくれたLBに感謝します

どうやら、GCCの同等物は(テストされていません):

#pragma message "BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION)
于 2009-10-13T19:23:01.050 に答える
15

私の知る限り、「#error」は文字列のみを出力します。実際、quotes を使用する必要さえありません

「BOOST_VERSION」を使用して、意図的に間違ったさまざまなコードを書いてみましたか? おそらく、「blah[BOOST_VERSION] = foo;」のようなものでしょう。「文字列リテラル 1.2.1 は配列アドレスとして使用できません」のようなメッセージが表示されます。きれいなエラー メッセージにはなりませんが、少なくとも関連する値が表示されます。値を示すコンパイルエラーが見つかるまで、いじってみることができます。

于 2009-10-13T18:52:50.977 に答える
5
#define a <::BOOST_VERSION>
#include a
MSVC2015 : 致命的なエラー C1083: インクルード ファイルを開けません: '::106200': そのようなファイルまたはディレクトリはありません

長所

  • 組み込みのマクロスで動作
  • preprocess to file無効なトークンが存在する場合でも、有効になっていても機能します。
#define a <::'*/`#>
#include a
MSVC2015 : 致命的なエラー C1083: インクルード ファイルを開けません: '::'*/`#': そのようなファイルまたはディレクトリはありません
GCC4.x : 警告: 終端の ' 文字 [-Winvalid-pp-token] がありません
<:: '*/`#>

短所

  • インクルード ファイル パスの無効な文字が原因で失敗することがあります。プレフィックスを変更することで修正できます (以下の更新セクションを参照してください)。

更新

GCC 4.7.x 以下の場合、出力で次のエラーがスローされます。

エラー: #include には "FILENAME" または <FILENAME> が必要です

プレフィックスを変更できることを修正するには:

#define a <.__cplusplus>
#include a
fatal error: .201103L: No such file or directory
于 2018-01-28T18:09:15.140 に答える
3

You could also preprocess the source file and see what the preprocessor value evaluates to.

于 2009-10-13T18:58:53.973 に答える
2

BOOST_VERSIONビルドシステムの一部として、印刷してコンパイルして実行するプログラムを作成できます。そうでなければ、私はあなたが運が悪いと思います。

于 2009-10-13T18:30:33.347 に答える
2

何方をお探しですか

#if BOOST_VERSION != "1.2"
#error "Bad version"
#endif

BOOST_VERSION が文字列の場合は良くありませんが、メジャー、マイナー、およびリビジョン番号に対して個別の整数が定義されている場合もあります。

于 2009-10-13T18:56:32.913 に答える
2

プリプロセッサの出力を見ることは、あなたが求める答えに最も近いものです。

あなたがそれを(そして他の方法で)除外したことは知っていますが、その理由はわかりません。解決すべき十分な具体的な問題がありますが、「通常の」方法がうまく機能しない理由を説明していません。

于 2009-10-13T19:02:18.913 に答える
1

マクロの使用方法については、Boost のドキュメントも参照してください。

http://www.boost.org/doc/libs/1_37_0/libs/config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.boost_helper_macrosBOOST_VERSIONからの参照:

ブースト バージョン番号を XXYYZZ 形式で記述します。 (BOOST_VERSION % 100)はサブマイナー バージョン、はマイナー バージョン、 は メジャー バージョンです。((BOOST_VERSION / 100) % 1000)(BOOST_VERSION / 100000)

于 2009-10-13T19:43:36.130 に答える
1

BOOST_VERSION は、ブースト ヘッダー ファイル version.hpp で定義されます。

于 2009-10-13T19:04:03.990 に答える