17

I have a C program with a lot of optimizations that can be enabled or disabled with #defines. When I run my program, I would like to know what macros have been defined at compile time.

So I am trying to write a macro function to print the actual value of a macro. Something like this:

SHOW_DEFINE(X){\
  if( IS_DEFINED(X) )\
      printf("%s is defined and as the value %d\n", #X, (int)X);\
  else\
      printf("%s is not defined\n", #X);\
}

However I don't know how to make it work and I suspect it is not possible, does anyone has an idea of how to do it?

(Note that this must compile even when the macro is not defined!)

Jens
  • 69,818
  • 15
  • 125
  • 179
Ben
  • 7,372
  • 8
  • 38
  • 46
  • Related, in case you got here searching for something else: if you just want to find out stuff about macros that standard headers define, not actually make your program print them, see [Listing C Constants/Macros](//stackoverflow.com/q/2421499) for stuff like `gcc -dM`, and [how to find the source of some macros](//stackoverflow.com/q/11257455) – Peter Cordes Jan 17 '20 at 22:45

11 Answers11

36

As long as you are willing to put up with the fact that SOMESTRING=SOMESTRING indicates that SOMESTRING has not been defined (view it as the token has not been redefined!?!), then the following should do:

#include <stdio.h>

#define STR(x)   #x
#define SHOW_DEFINE(x) printf("%s=%s\n", #x, STR(x))

#define CHARLIE -6
#define FRED 1
#define HARRY FRED
#define NORBERT ON_HOLIDAY
#define WALLY

int main()
{
    SHOW_DEFINE(BERT);
    SHOW_DEFINE(CHARLIE);
    SHOW_DEFINE(FRED);
    SHOW_DEFINE(HARRY);
    SHOW_DEFINE(NORBERT);
    SHOW_DEFINE(WALLY);

return 0;
}

The output is:

BERT=BERT
CHARLIE=-6
FRED=1
HARRY=1
NORBERT=ON_HOLIDAY
WALLY=
Dipstick
  • 9,854
  • 2
  • 30
  • 30
4

Writing a MACRO that expands to another MACRO would require the preprocessor to run twice on it.
That is not done.

You could write a simple file,

// File check-defines.c
int printCompileTimeDefines()
{
#ifdef DEF1
  printf ("defined : DEF1\n");
#else // DEF1
  printf ("undefined: DEF1\n");
#endif // DEF1
// and so on...
}

Use the same Compile Time define lines on this file as with the other files.
Call the function sometime at the start.

If you have the #DEFINE lines inside a source file rather than the Makefile,
Move them to another Header file and include that header across all source files,
including this check-defines.c.

Hopefully, you have the same set of defines allowed across all your source files.
Otherwise, it would be prudent to recheck the strategy of your defines.


To automate generation of this function,
you could use the M4 macro language (or even an AWK script actually).
M4 becomes your pre-pre-processor.

nik
  • 13,254
  • 3
  • 41
  • 57
  • Accepted for the m4 answer. This become easy when you add another preprocessing step. I did SHOW_DEFINE(X,Y,Z ... ) which is even better. However it makes sens because I need m4 for other stuffs. – Ben Jul 22 '09 at 12:32
2
#ifdef MYMACRO
  printf("MYMACRO defined: %d\r\n", MYMACRO);
#endif

I don't think what you are trying to do is possible. You are asking for info at runtime which has been processed before compilation. The string "MYMACRO" means nothing after CPP has expanded it to its value inside your program.

kjfletch
  • 5,394
  • 3
  • 32
  • 38
  • well, this is what I would like to avoid, since I have many of them with #ifdef #else #endif. – Ben Jul 22 '09 at 11:49
2

You did not specify the compiler you were using. If this is gcc, gcc -E may help you, as it stops after the preprocessing stage, and prints the preprocessing result. If you diff a gcc -E result with the original file, you may get part of what you want.

Yuval F
  • 20,565
  • 5
  • 44
  • 69
2

Why not simply testing it with the preprocessor ?

 #if defined(X)
      printf("%s is defined and as the value %d\n", #X, (int)X);
 #else
      printf("%s is not defined\n", #X);
 #endif

One can also embed this in another test not to print it everytime:

 #if define(SHOW_DEFINE)
 #if defined(X)
      printf("%s is defined and as the value %d\n", #X, (int)X);
 #else
      printf("%s is not defined\n", #X);
 #endif
 #endif
philant
  • 34,748
  • 11
  • 69
  • 112
  • @philippe, Well, that's what I and kjfletch seem to have suggested. But he wants to avoid writing all that down, which is why I suggest M4 or AWK scripting. – nik Jul 22 '09 at 12:03
  • This is what I do now, the list is never up to date and it needs a special file just for this purpose :( – Ben Jul 22 '09 at 12:05
2

Based on Chrisharris, answer I did this. Though my answer is not very nice it is quite what I wanted.

#define STR(x)   #x
#define SHOW_DEFINE(x) printf("%s %s\n", #x, strcmp(STR(x),#x)!=0?"is defined":"is NOT    defined")

Only bug I found is the define must not be #define XXX XXX (with XXX equals to XXX).

Ben
  • 7,372
  • 8
  • 38
  • 46
1

Wave library from boost can be helpful also to do what you want. If your project is big enough, I think it is worth trying. It is a C++ preprocessor, but they are the same any way :)

Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
1

I believe what you are trying to do is not possible. If you are able to change the way your #defines work, then I suggest something like this:

#define ON 1
#define OFF 2

#define OPTIMIZE_FOO ON
#define OPTIMIZE_BAR OFF

#define SHOW_DEFINE(val)\
    if(val == ON) printf(#val" is ON\n");\
    else printf(#val" is OFF\n");
Clay
  • 1,159
  • 1
  • 9
  • 20
1

It is not possible indeed, the problem being the "not defined" part. If you'd relied on the macro values to activate/deactivate parts of your code, then you could simply do:

#define SHOW_DEFINE(X) \
do { \
if (X > 0) \
    printf("%s %d\n", #X, (int)X);   \
else \
    printf("%s not defined\n", #X);   \
} while(0)
0

This question is very close from Macro which prints an expression and evaluates it (with __STRING). Chrisharris' answer is very close from the answer to the previous question.

Community
  • 1
  • 1
bortzmeyer
  • 34,164
  • 12
  • 67
  • 91
0

you can use an integer variable initialized to 1. multiply the #define with this variable and print the value of variable.