C preprocessor: expand macro in a #warning

2019-01-21 10:51发布

I would like to print a macro value (expand the macro) in the #warning directive.

For example, for the code:

#define AAA 17
#warning AAA = ???

The desired compile-time output would be

warning: AAA = 17

What do I use for ???, or, how do I augment the code?

4条回答
够拽才男人
2楼-- · 2019-01-21 11:19

You can use the preprocessor directive #pragma message.

Example:

#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; }

The output may look like this:

$ gcc test.c
test.c:5:9: note: #pragma message: content of AAA: 123
 #pragma message("content of AAA: " STR(AAA))
         ^

For reference:

查看更多
疯言疯语
3楼-- · 2019-01-21 11:22

I wouldn't recommend using #warning, since it is not standard C. Besides, what is there that you want to warn against but not throw an error against? Warnings is typically something the compiler uses when you are doing something that is suspicious our outright dangerous, yet allowed by the C standard. You have no such case in normal application, you are going to want it to either compile flawlessly or not at all. Therefore I'd use standard #error and not non-standard #warning.

You can't type the actual contents of the pre-processor definition. Something like this might suffice:

#if (AAA < SOMETHING) && (AAA > SOMETHING_ELSE)
  #error AAA is bad.
#endif

I think this is detailed enough for the programmer. However, if you really want more details and you have a modern C compiler, you can use static_assert. Then you can achieve something close to what you want:

#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));

this macro mess should print AAA is 17. An explanation over how these macros work can be found here.

I'm not sure whether static_assert was included in C99 or C11, it is certainly in C11. You might have to use some GCC extension to enable it.

查看更多
我欲成王,谁敢阻挡
4楼-- · 2019-01-21 11:26

Many times I have my Makefile generate a local generated.h file that contains the desired definitions.

generated.h:  Makefile
        echo >generated.h "// WARNING: generated file. Change Makefile instead"
        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"

The need for #include "generated.h" is obvious.

Naturally you can spin any complexity here, but if it gets more then a few lines you may want to put the complexity into a separate script as cluttered Makefiles can be a horrid maintenance issue. With a little Imagination you can have loops generating large numbers of tests from a little input.

Having the generated.h target depend on Makefile is critical to assure generated.h is remade if the instructions in the target change. If you have a separate generated.sh script that too would be on the dependency list.

Disclaimer: have not tested for real.

查看更多
爷的心禁止访问
5楼-- · 2019-01-21 11:36

If you really want to emit a warning, the following will work, too. However, it depends on C99 being enabled (works with gcc 4.8.2 or later, not tested on earlier versions):

#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
查看更多
登录 后发表回答