web-dev-qa-db-ja.com

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

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

#error BOOST_VERSION

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

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

108
Jim Hunziker

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)
57
Bojan Resnik

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として定義""文字列として定義"、および"定義されているが値なし"変数の場合、問題なく動作します。 "not defined"変数の場合のみ、元の変数名とまったく同じように表示されます。あなたはそれに慣れなければなりません-あるいは誰かがより良い解決策を提供できるかもしれません。

111
Jackie Yeh

これは元のクエリから長い時間が経過したことを知っていますが、これはまだ有用かもしれません。

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

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

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

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

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

使い方:

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

#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(引用符なし)を先行する文字列と連結できないため、プリプロセッサ警告が発生します。

次に、プリプロセッサの文字列化を検討します(かつて文字列化と呼ばれていましたが、ドキュメント内のリンクは変更された用語を反映するように変更されました。あなたのリンク。))演算子。これはマクロの引数にのみ作用し、展開されていない引数を二重引用符で囲まれた引数に置き換えます。副<文>この[前述の事実の]結果として、それ故に、従って、だから◆【同】consequently; therefore <文>このような方法で、このようにして、こんなふうに、上に述べたように◆【同】in this manner <文>そのような程度まで<文> AひいてはB◆【用法】A and thus B <文>例えば◆【同】for example; as an example:

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

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

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

91
Chris Barry

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

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

13
KeyserSoze

ブーストなし:

  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 ()
{

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

preprocess to fileは、無効なトークンが存在する場合でも有効です。

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

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
4
UweBaemayr

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

3
fbrereto

何方をお探しですか

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

BOOST_VERSIONが文字列である場合、私が想定したように素晴らしいことではありませんが、メジャー番号、マイナー番号、およびリビジョン番号に対して定義された個々の整数もあります。

2
user47559

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

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

2
dwc

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

を参考に BOOST_VERSIONから 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_macros

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

1
bn.

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

1
David Harris

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

1
Chris Lutz