#warning ディレクティブでマクロ値を出力 (マクロを展開) したいと考えています。
たとえば、コードの場合:
#define AAA 17
#warning AAA = ???
望ましいコンパイル時の出力は次のようになります。
warning: AAA = 17
??? には何を使用しますか、またはコードをどのように拡張しますか?
#warning ディレクティブでマクロ値を出力 (マクロを展開) したいと考えています。
たとえば、コードの場合:
#define AAA 17
#warning AAA = ???
望ましいコンパイル時の出力は次のようになります。
warning: AAA = 17
??? には何を使用しますか、またはコードをどのように拡張しますか?
プリプロセッサ ディレクティブを使用できます#pragma message
。
例:
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define AAA 123
#pragma message "content of AAA: " STR(AAA)
int main() { return 0; }
出力は次のようになります。
$ gcc test.c
test.c:5:9: note: #pragma message: content of AAA: 123
#pragma message("content of AAA: " STR(AAA))
^
参考のため:
本当に警告を発したい場合は、以下も機能します。ただし、有効になっている C99 に依存します (gcc 4.8.2 以降で動作しますが、以前のバージョンではテストされていません)。
#define N 77
#define __STRINGIFY(TEXT) #TEXT
#define __WARNING(TEXT) __STRINGIFY(GCC warning TEXT)
#define WARNING(VALUE) __WARNING(__STRINGIFY(N = VALUE))
#if N == 77
_Pragma (WARNING(N))
#endif
#warning は標準の C ではないため、使用はお勧めしません。また、警告したいがエラーを発生させたくないものは何ですか? 警告は通常、C 標準では許可されているものの、明らかに危険であると疑われる何かを実行しているときにコンパイラが使用するものです。通常のアプリケーションではそのようなケースはありません。問題なくコンパイルするか、まったくコンパイルしないようにする必要があります。したがって、非標準の #warning ではなく、標準の #error を使用します。
プリプロセッサ定義の実際の内容を入力することはできません。このようなもので十分かもしれません:
#if (AAA < SOMETHING) && (AAA > SOMETHING_ELSE)
#error AAA is bad.
#endif
これはプログラマにとって十分に詳細であると思います。ただし、本当に詳細が必要で、最新の C コンパイラを使用している場合は、static_assertを使用できます。次に、目的に近いものを実現できます。
#include <assert.h>
#define xstr(s) str(s)
#define str(s) #s
#define err_msg(x) #x " is " xstr(x)
#define AAA 17
static_assert(AAA != 17, err_msg(AAA));
このマクロの混乱は、AAA is 17 を出力するはずです。これらのマクロがどのように機能するかについての説明は、ここにあります。
static_assert が C99 に含まれていたのか、C11 に含まれていたのかはわかりませんが、C11 には含まれています。有効にするには、GCC 拡張機能を使用する必要がある場合があります。
多くの場合、必要な定義を含むローカルの generated.h ファイルを Makefile で生成します。
generated.h: Makefile echo > generated.h "// 警告: 生成されたファイル。代わりに Makefile を変更してください" 日付 >> generated.h '+// %Y-%m-%d %H:%M:%S に生成されました' echo >> generated.h "#if AAA == AAA_bad" echo >> generated.h "#warning \"AAA = $(AAA_bad)\"" echo >> generated.h "#endif"
#include "generated.h" の必要性は明らかです。
もちろん、ここで任意の複雑さをスピンすることができますが、数行を超える場合は、混乱した Makefile が恐ろしいメンテナンスの問題になる可能性があるため、複雑さを別のスクリプトに入れたいと思うかもしれません。少し想像力を働かせれば、小さな入力から多数のテストを生成するループを作成できます。
generated.h ターゲットを Makefile に依存させることは、ターゲット内の命令が変更された場合に generated.h が確実に再作成されるようにするために重要です。別の generated.sh スクリプトがある場合、それも依存リストに含まれます。
免責事項:実際にテストしていません。