52

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?

AstroCB
  • 12,337
  • 20
  • 57
  • 73
elomage
  • 4,334
  • 2
  • 27
  • 23
  • 3
    According to the C standard from 1999, you only have `#error` for something like that and it does not expand any macros, it just prints the text literally and causes compilation to stop. What are you trying to achieve with this anyway? – Alexey Frunze Sep 28 '12 at 09:41
  • I have a hierarchy of many makefiles that define AAA in various ways, depending on the make target parameters. I would like to verify that the definition is correct for the target. And I would not want to create a list of #if AAA = 1 ... #warning "is 1"... – elomage Sep 28 '12 at 09:44
  • Also, this is for the embedded world with no displays, so I can not easily test the macro value by adding something like printf( #AAA ); and check it at runtime. – elomage Sep 28 '12 at 09:58
  • So you do `#if A == 1\#error A = 1\#elif A == 2\#error A = 2\#endif`. – Alexey Frunze Sep 28 '12 at 10:00
  • 1
    @AlexeyFrunze That is exactly what I want to avoid - see my comment above. I may not know all the possible values, or there might be too many of those. – elomage Sep 28 '12 at 10:09
  • Possible duplicate of [How do I show the value of a #define at compile-time?](http://stackoverflow.com/questions/1562074/how-do-i-show-the-value-of-a-define-at-compile-time) – moooeeeep Feb 18 '16 at 15:55

5 Answers5

63

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:

moooeeeep
  • 31,622
  • 22
  • 98
  • 187
  • You should mention the compiler(s) with which this works. `#pragma's` are implementation-specific. – Alexey Frunze Sep 28 '12 at 10:26
  • Works with gcc version 4.5.3 (GNU GCC patched mspgcc-20110716), thanks. – elomage Sep 29 '12 at 13:11
  • 3
    be sure to use `#pragma message` instead of `#message` or `#warning` – Fantastory Aug 07 '13 at 09:57
  • 1
    This is a great start ... but it's worth noting that this prints the expansion of the macro ... not the value. If you have a macro that recursively expands to lengthy (but simple) math, possibly in terms of other macros, this likely will not help you much. – Cheetah Jul 29 '16 at 13:34
  • It would be nice if `#pragma message` allowed to generate warnings. `#pragma GCC diagnostic warning "message "` does not allow it (https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html). – pevik Jan 04 '18 at 20:12
  • If the macro you're trying to expand has more than one argument, you're going to want a variation of this answer: `#define STR_HELPER(...) #__VA_ARGS__` `#define STR(...) STR_HELPER(__VA_ARGS__)` – Cameron Tacklind Feb 10 '19 at 09:07
  • @Cheetah Is there a way to calculate and print the actual value? – endolith Jun 09 '22 at 16:56
9

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
Aconcagua
  • 24,880
  • 4
  • 34
  • 59
7

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • see also [this question](http://stackoverflow.com/q/3385515/1025391) for static assertions in C – moooeeeep Sep 28 '12 at 11:46
  • I just needed an informative message with the value to confirm my suspicion that a global internal parameter was incorrect for a particular case. No "bad" values here. It turned out that it was incorrect. But thanks for the static_assert, it works since g++ version 4.3 with the option -std=c++0x , and gcc version 4.6 has static_assert aliased to _Static_assert without the option. – elomage Sep 29 '12 at 13:25
  • @elomage _Static_assert is actually a keyword in C now, since C11. contains a macro static_assert, which expands to _Static_assert. Either form should be fine to use since they are both standard. – Lundin Sep 29 '12 at 18:45
  • "Why would you..." Because if I'm changing something in the core support libraries of the MCU I'm using, for debugging purposes (like redefining the `HAL_SYSTEM_RESET()` macro from an actual control register write to "while(1)" so I can inspect the state with a debugger), then I want the assurance that said build never reaches a live environment. I still need it to build for the test to work. Of course, only works if you run a policy of no warnings in a production build... – Jostikas Jul 08 '21 at 07:28
  • 1
    @Jostikas Version control is really useful and the correct solution to the problem you describe. Simply dump your modified code in a branch used for experimentation. – Lundin Jul 08 '21 at 07:34
  • True. I'd still prefer a big red verbose message to go with it: If nothing else, it serves as a very visible documentation of what functionality is expected to be broken in said experimental branch, and where said breaks are. – Jostikas Jul 08 '21 at 08:58
2

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.

Gilbert
  • 3,740
  • 17
  • 19
0

Another simple method is, especially when you are dealing with a Makefile project (like linux, u-boot, qemu, ..), you can see the pre-processed result of the file.
For example,

to see preprocessed file of arch/arm64/kernel/head.S,
you can do make arch/arm64/kernel/head.s. (small s).

to see preprocessed file of foo/bar/baz.c,
you can do make foo/bar/baz.i

The macros are all expanded to the final value.

Chan Kim
  • 5,177
  • 12
  • 57
  • 112