1. ホーム
  2. macros

[解決済み] コンパイル時に#defineの値を表示するには?

2022-04-24 08:53:29

質問

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

#error BOOST_VERSION

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

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

どのように解決するのですか?

最初の問い合わせからずいぶん時間が経っていますが、これはまだ役に立つかもしれません。

これはGCCでstringify演算子 "#"を使って行うことができますが、2段階必要です。

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

そして、マクロの値を表示することができます。

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

を参照してください。3.4 文字列化 (gccオンラインドキュメント) を参照してください。

どのように機能するか

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

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