コンパイル時に#defineの値を表示するにはどうすればよいですか?


123

私のコードがどのバージョンのBoostを使用していると考えているかを調べようとしています。私はこのようなことをしたいです:

#error BOOST_VERSION

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

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


7
将来の訪問者のために... Chris Barryが最後に一般化されたソリューションを提供します(Boost固有のものはありません)。
jww 2015

回答:


117

これは元のクエリから長い時間が経過していることを知っていますが、それでもまだ役立つ場合があります。

これは、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を呼び出して、展開された値を引用符で囲みます。


3
私はそれが2つの段階が必要となる理由として好奇心が強い
ヴィンセントFourmond

4
@VincentFourmond XSTRステージがないと、マクロは展開されません。したがって、#define ABC 42を実行した場合、\ n STR(ABC)は「ABC」になります。gcc.gnu.org/onlinedocs/cpp/Stringification.htmlを
rob05c

これは、ABCをに置き換えるなど、Xcode 8でもうまく機能し__IPHONE_9_3ます。
funroll 2016年

GCCの用語は、今あるURL、変更されているようだ、とそれにhttps://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing
クリス・バリー

119

BOOST_PP_STRINGIZE C ++の優れたソリューションのようですが、通常の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"

「intergerと定義」「文字列として定義」、および「定義されたが、何の価値」変数は、彼らがうまく動作しません。「未定義」変数についてのみ、元の変数名とまったく同じように表示されました。あなたはそれに慣れなければなりません-あるいは多分誰かはより良い解決策を提供することができます。


優れた!ARM RVCTの経験はありますか?それはGCCのように何の「文字列化」機能がないようだinfocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/...
xdan

2
素晴らしいソリューション。しかし、複雑な構造体のサイズなど、コンパイル時の計算値のサイズを表示したい場合は、これを実行できますか?この回答で提案されている方法はDEFINED_INT=(sizeof(MY_STRUCT))sizeof演算子が評価されずにを生成するようです。
Carl

(コメントの追加:予期しないことではありません。評価するのはプリプロセッサではなくコンパイラですが、sizeofこれを達成するための賢い方法があるかどうかはまだ気になります。)
Carl

@xdan良い解決策ですが、残念ながら次のようなことには対応していません#define masks {0xff, 0xaf, 0x0f}
Simon Bagley

59

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)

5
診断プラグマ、と呼ばれているgcc.gnu.org/onlinedocs/gcc/...
LB40

4
定義がBOOST_PP_STRINGIZE含まれてい、短くて、コピー/貼り付けが可能であれば、いいでしょう。
Timmmm 2017

gccで問題なく動作します:)
Thomas Legris

14

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

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


BOOST_VERSIONは整数なので、これは機能しませんでしたが、std::vector<BOOST_VERSION>;gcc 4.4.1の次のステートメントで確認できました。ありがとう!
ジムハンジカー、

Visual C ++では、Bojan Resnikの回答を使用する必要があることに注意してください。
ラファエルサンピエール

これを機能させようとしましたが、GCCが表示するエラーメッセージは残念ながら説明がありませんでした。しかしそれを言及するための+1。
Chris Lutz、

14

ブーストなし:

  1. 同じマクロを再度定義すると、コンパイラHIMSELFが警告を出します。

  2. 警告から、前の定義の場所を確認できます。

  3. 以前の定義のviファイル。

ambarish@axiom:~/cpp$ g++ shiftOper.cpp
shiftOper.cpp:7:1: warning: "LINUX_VERSION_CODE" redefined
shiftOper.cpp:6:1: warning: this is the location of the previous definition

#define LINUX_VERSION_CODE 265216
#define LINUX_VERSION_CODE 666

int main ()
{

}

これは簡単で簡単です。
Tmx 2018年

1
それ自体:コンパイラには性別がない
Sky

これはなどの定義済みマクロでは機能しません__cplusplus
ManuelAtWork

10

Microsoft C / C ++では、組み込みを使用して_CRT_STRINGIZE()定数を出力できます。私のstdafx.hファイルの多くはこれらのいくつかの組み合わせを含んでいます:

#pragma message("_MSC_VER      is " _CRT_STRINGIZE(_MSC_VER))
#pragma message("_MFC_VER      is " _CRT_STRINGIZE(_MFC_VER))
#pragma message("_ATL_VER      is " _CRT_STRINGIZE(_ATL_VER))
#pragma message("WINVER        is " _CRT_STRINGIZE(WINVER))
#pragma message("_WIN32_WINNT  is " _CRT_STRINGIZE(_WIN32_WINNT))
#pragma message("_WIN32_IE     is " _CRT_STRINGIZE(_WIN32_IE))
#pragma message("NTDDI_VERSION is " _CRT_STRINGIZE(NTDDI_VERSION)) 

このようなものを出力します:

_MSC_VER      is 1915
_MFC_VER      is 0x0E00
_ATL_VER      is 0x0E00
WINVER        is 0x0600
_WIN32_WINNT  is 0x0600
_WIN32_IE     is 0x0700
NTDDI_VERSION is 0x06000000

5
#define a <::BOOST_VERSION>
#include a
MSVC2015:致命的なエラーC1083:インクルードファイルを開けません: ':: 106200':そのようなファイルまたはディレクトリはありません

場合でも動作しpreprocess to file、無効なトークンが存在する場合であっても、ISは有効:

#define a <::'*/`#>
#include a
MSVC2015:致命的なエラーC1083:インクルードファイルを開けません: '::' * / `# ':そのようなファイルまたはディレクトリはありません
GCC4.x:警告:終了文字'がありません[-Winvalid-pp-token]
#define a <:: '* / `#>

私はただ言うBuild error: #include expects "FILENAME" or <FILENAME>。はぁ。
エンドリス

@endolithコンパイラとバージョンは?
Andry、2018年

DP8051 Keil社の9.51 :)
endolith

@endolithこのコンパイラは前処理が非常に制限されているようです:keil.com/support/man/docs/c51/c51_pp_directives.htmしかし、鉱山側ではほぼ期待どおりに機能します。次のような無効な文字の一部を削除しました'*** WARNING C318 IN LINE 2 OF test.c: can't open file '::*/`'
Andry

おかげで、私が使用していたコンパイラーにプラグマ・メッセージのものが実装されなかったので、これは私を救いました。
CodeMonkey

3

また、ソースファイルを前処理して、プリプロセッサ値の評価を確認することもできます。


2

何方をお探しですか

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

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


サブミッターは特定の値を(ただ)強制したくないと思います。現在の値が何であるかを見たいと思っています。
KeyserSoze 2009年

これは私のために働く唯一のものです。私は変更することができます#if VARIABLE == 123...その場で声明をし、構文の強調表示は、それが私はそれがあるかどうかだと思い値のかどうか私に語った
endolith

2

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

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


これはおそらく一般的な問題に対する正しい答えです。
jww 2016年

1

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


ヘッダーで定義されたソフトウェアバージョンの場合は、おそらく安全です(そしてそれは良い答えです)。ただし、一般的な解決策として、テストアプリと実際のアプリの#defineの値が同じになる可能性があります-インクルードパスに応じて、その値を設定するために使用できる他の#define 、コンパイラに渡されるCFLAGSなど
KeyserSoze

実際のプログラムから印刷します。グラフィカルな場合は、[バージョン情報]ダイアログに配置します。コマンドラインの場合、それをオプションにします(多分--versionの一部)。デーモンの場合は、ログファイルに書き込みます。埋め込まれている場合は、他の方法を見つけます。
divegeek

@swillden-OPは、実行時ではなく、コンパイル時にそれを求めていました。
Chris Lutz、

これはクロスコンパイラベースのビルドを壊す傾向もあります
Craig Ringer


1

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

を参照してBOOST_VERSIONhttp//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_macrosから:

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


0

#errorの代わりに、マクロが使用される直前に、マクロを再定義してください。コンパイルは失敗し、コンパイラーはマクロに適用すると思われる現在の値を提供します。

#define BOOST_VERSION何とか

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