web-dev-qa-db-ja.com

Cプリプロセッサ:#warningでマクロを展開します

#warningディレクティブにマクロ値(マクロを展開)を出力したいと思います。

たとえば、コードの場合:

#define AAA 17
#warning AAA = ???

望ましいコンパイル時の出力は

warning: AAA = 17

???に何を使用しますか、またはコードをどのように増強しますか?

38
elomage

プリプロセッサディレクティブ#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))
         ^

参考のために:

46
moooeeeep

あなたが本当に警告を発したいなら、以下も機能します。ただし、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
8
Aconcagua

標準のCではないため、#warningを使用することはお勧めしません。さらに、警告はしたいがエラーをスローしたくないものは何ですか?通常、警告は、完全に危険であるが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を17に出力するはずです。これらのマクロがどのように機能するかについての説明は here です。

Static_assertがC99とC11のどちらに含まれていたかはわかりませんが、C11に含まれていることは確かです。有効にするには、GCC拡張機能を使用する必要がある場合があります。

7
Lundin

多くの場合、必要な定義を含むローカルのgenerated.hファイルをMakefileで生成します。

 generated.h:Makefile 
 echo> generated.h "//警告:生成されたファイル。代わりにMakefileを変更してください" 
 date >> generated.h '+ // generated on% 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スクリプトがある場合、それも依存関係リストに含まれます。

免責事項:実際にテストしていない。

2
Gilbert