4

Can I combine macros while writing code for C or C++? If not, why? If yes, how?

I'm interested on how to solve the following (not correct and NOT compiling!!!) idea:

#define FREE(x) if((x)) {                                         \
#ifdef MEM_DEBUG_                                                 \
    fprintf(stderr, "free:%p (%s:%d)\n", (x), __FILE__, __LINE__); \
#endif                                                             \
    free((x)); }

So, what I want to achieve is this:

I want to define the macro FREE in way that it will include an extra line if I have the MEM_DEBUG defined.

I know, that for solving this I can have two defines for the FREE based on MEM_DEBUG, like:

#ifdef MEM_DEBUG
  #define FREE() something
#else 
  #define FREE() something else
#endif

but I'm just curios if there is another way!

Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167
  • 5
    You're using [reserved identifiers](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). – chris Dec 03 '13 at 09:15
  • @chris You're right about that... I'll modify the names to not to start with an underscore to not to let people mistakenly think that I work on an implementation. – Ferenc Deak Dec 03 '13 at 09:18
  • If this is used in C++ you should be shot. No, on a more serious note, in C++, you really really shouldn't even have to debug memory management if you properly use smart pointers. – rubenvb Dec 03 '13 at 09:18
  • 1
    @rubenvb When you work on inherited legacy code you will wonder what people call "C++" :P – Ferenc Deak Dec 03 '13 at 09:20
  • Maybe you can check this one for reference how to define conditional marcro: http://stackoverflow.com/questions/7372448/c-macro-to-conditionally-compile-code – Mine Dec 03 '13 at 09:22
  • Oh, and by the way, `free` does nothing if passed in a null pointer. – chris Dec 03 '13 at 09:23
  • @chris You're right too... and you also will wonder what you will get when taking over 20 year old "C++" code which still compiles, works, has no bugs, it's damn fast... but has not too much in common with todays' best practices or standards :) – Ferenc Deak Dec 03 '13 at 09:26
  • 'has no bugs' but you're adding debugging code? Anyway I'm afraid you have to put up with a bit of 'chat' if you use this site. – john Dec 03 '13 at 09:28
  • @john Sorry, I did not mention that I'm adding debugging code anywhere. This is just a pure theoretical question for the benefit of all the programmers about C/C++ macros. – Ferenc Deak Dec 03 '13 at 09:31
  • @rubenvb Outside of your university, in the real world where ordinary people live and have real coding constraints, all compilers do not always support the newest features of STL or C++11, neither do they always support boost or whatever is the library you're talking about with smart pointers. – Virus721 Dec 03 '13 at 09:34
  • OK, well the the effects of including a preprocessor directive within a macro are officially undefined. So there doesn't seem to be any way to do what you want. – john Dec 03 '13 at 09:35
  • You could just use normal if (MEM_DEBUG) and have it always be defined to 1 or 0. I guess it could also work having it defined to 1 or undefined/0 with `if (MEM_DEBUG-0)`. – domen Dec 03 '13 at 09:37
  • BTW. for memory debugging, you might want to use `memcheck` or similar. If looking for your own debugging solution, just overload your malloc/free and call originals with help of `dlsym()`. – domen Dec 03 '13 at 09:40
  • @fritzone Just because you think there aren't any bugs, doesn't mean there aren't any. This is especially true of 20 year old legacy code, which I'm guessing has no unit testing to speak of. – The Forest And The Trees Dec 03 '13 at 09:40
  • @TheForestAndtheTrees and ... You are right too (seems, everyone is right today :) )Definitely no unit tests in that piece of code :) I personally do not think there are no bugs in the code, our testing manager and customers think :P ... (and the latter is the more important) :D ... I wonder if they actually did use tho software for the last 19 years... – Ferenc Deak Dec 03 '13 at 09:45

2 Answers2

4

Yes, you can define macros to encapsulate the idea of doing something when the flag is set.

#ifdef MEM_DEBUG
#   define IF_MEM_DEBUG( ... ) __VA_ARGS__
#   define IF_MEM_NDEBUG( ... )
#else
#   define IF_MEM_DEBUG( ... )
#   define IF_MEM_NDEBUG( ... ) __VA_ARGS__
#endif

#define FREE(x) \
if((x)) { \
    IF_MEM_DEBUG( \
        fprintf(stderr, "free:%p (%s:%d)\n", (x), __FILE__, __LINE__); \
    ) \
    free((x)); \
}
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
2

No, it's not possible to put preprocessing directives (lines starting with #) inside a macro definition. So the only thing you can do is the second method you mention - put the definitions inside the conditionals.

Of course, if you're working on a bigger macro and only a part of it is #if-dependent, you can isolate the dependent part into a separate macro and use this in the bigger one, to keep the divergent definitions as small as possible.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • 1
    @user1233963 Ouch. I don't think that's really possible. The first preprocessor would eat the `#define` (and probably bail out on a syntax error). You would have to somehow escape the `#` (and also `\ `) characters for the first preprocessor run - a maintenance **nightmare.** Just don't. – Angew is no longer proud of SO Dec 03 '13 at 09:21