views:

806

answers:

5

I have a symbol defined globally that needs to be conditionally undefined for a given subset of my source files. All of the files that require special treatment are already wrapped in pre- and post-inclusions:

pre.h:

#undefine mysymbol // [1]

post.h:

#define mysymbol MY_SYMBOL_DEFINITION // [2]

My problem is that the pre.h and post.h can be included multiple times for a given source file due to various inclusion chaining. As such, I need [1] to happen the first time pre.h is included and I need [2] to happen the last time that post.h is included. Conceptually:

pre         // undefine
   pre      // no-op
      pre   // no-op
      post  // no-op
   post     // no-op
post        // redefine

Since I am using gcc 3.4.6, I do not have access to the push and pop macro pragmas that might otherwise solve this issue for me.

How can I emulate that behavior with the remaining preprocessor functionality?

I was attempting to do something like increment/decrement a value with the preprocessor but I'm not sure that's possible.

EDIT: "What am I really trying to do?"

We have macros to replace new with new(__FILE__, __LINE__) -- see my other question on this topic -- and we need to undefine those macros in the set of source files wrapped by the pre- and post-includes described above because we were unable to create a macro that's compatible with the placement new syntax used therein.

A: 

Incrementing/decrementing a value at compile time is probably possible with meta-programmign wizardry a-la Loki. But are you sure this is necessary?

Why is your h file included so many time? Why not use an include guard?

Assaf Lavie
The point of the pre/post headers is to wrap each file they're included in. Include guards will break that behavior as the pre/post would only be included once per compilation unit.
David Citron
A: 

have you tried

pre.h

#ifndef MYMACROGUARD
#undef MYMACRO
#define MYMACROGUARD MYMACROGUARD+1
#endif

post.h

#if MYMACROGUARD <= 0
#undef MYMACROGUARD
#else
#define MYMACROGUARD MYMACROGUARD-1
#endif

I don't have access to a compile right now so

EDIT: tested with this code

#define MYMACRO
#include<iostream>
using namespace std;
int main()
{
#ifdef MYMACRO
cout<<"1"<<endl;
#endif
#include <pre.h>
#ifdef MYMACRO
cout<<"2"<<endl;
#endif
#include <pre.h>
#ifdef MYMACRO
cout<<"3"<<endl;
#endif
#include <post.h>
#ifdef MYMACRO
cout<<"4"<<endl;
#endif
#include <post.h>
#ifdef MYMACRO
cout<<"5"<<endl;
#endif
}

$> g++ -w -I. test.cpp && ./a.out
1
5

KitsuneYMG
I already tried this but numerical evaluation appears not to happen in the preprocessor. Also you cannot redefine the guard. Finally, the macro itself (MYMACROGUARD) is not replaced in the replacement text.
David Citron
That's working for you by coincidence because you only have two levels of nesting. If you tried three levels of nesting it would fail.
David Citron
I've tried gcc and g++ and I can't make #define SOME SOME+1 working. It redefines macro without adding. When I try to use SOME in my code it expand to SOME+1. And testing with #if <= SOME doesn't works.
klew
I tried in codepad.org (they seem to use g++) - complains about macro redefinition.
xtofl
A: 

If you know the maximum depth of recursion, then you should be able to simulate the push/pop by defining a new macro at each level. For the 3 level example you give, that would look something like:

Pre.h:

#ifdef RECURSION_COUNT_1
 #ifdef RECURSION_COUNT_2
  #ifdef RECURSION_COUNT_3
   #error Recursion level too deep
  #else
   #define RECURSION_COUNT_3
  #endif
 #else
  #define RECURSION_COUNT_2
 #endif
#else
 #define RECURSION_COUNT_1
 #undef YOUR_SYMBOL_HERE
#endif

Post.h

#ifdef RECURSION_COUNT_3
 #undef RECURSION_COUNT_3
#else
 #ifdef RECURSION_COUNT_2
  #undef RECURSION_COUNT_2
 #else
  #ifdef RECURSION_COUNT_1
   #undef RECURSION_COUNT_1
   #define YOUR_SYMBOL_HERE
  #endif
 #endif
#endif
Interesting solution, if a bit verbose :-)
David Citron
Hmm, It would be cleaner to leave only one of these macros defined at a time- then the order could take care of the else branches like in klew's solution.
+4  A: 

You can add somethig like this to your pre.h file:

... 

#ifdef COUNT
#if COUNT == 2
#undef COUNT
#define COUNT 3
#endif

#if COUNT == 1
#undef COUNT
#define COUNT 2
#endif

#else
#define COUNT 1

... here put your pre.h code

#endif

And in post.h:

#ifdef COUNT
#if COUNT == 1
#undef COUNT
#endif

#if COUNT == 2
#undef COUNT
#define COUNT 1
#endif

#if COUNT == 3
#undef COUNT
#define COUNT 2
#endif

...    

#end

#ifndef COUNT

... here put your pre.h code

#endif

But you need to know how deep can you go.

klew
You and Ben Murphy had similar ideas :-)
David Citron
A: 

pre.h

#ifndef MYSYMBOLUNDEFFERSTACK
#define MYSYMBOLUNDEFFERSTACK 0
#else
#define MYSYMBOLUNDEFFERSTACKTMP (MYSYMBOLUNDEFFERSTACK+1)
#undef MYSYMBOLUNDEFFERSTACK
#define MYSYMBOLUNDEFFERSTACK MYSYMBOLUNDEFFERSTACKTMP
#undef MYSYMBOLUNDEFFERSTACKTMP
#endif

#if MYSYMBOLUNDEFFERSTACK == 0
#undef mysymbol
#endif

post.h

#ifndef MYSYMBOLUNDEFFERSTACK
#error "Async Post.h"
#else
#define MYSYMBOLUNDEFFERSTACKTMP (MYSYMBOLUNDEFFERSTACK-1)
#undef MYSYMBOLUNDEFFERSTACK
#define MYSYMBOLUNDEFFERSTACK MYSYMBOLUNDEFFERSTACKTMP
#undef MYSYMBOLUNDEFFERSTACKTMP
#endif

#if MYSYMBOLUNDEFFERSTACK == 0
#define mysymbol "MY_SYMBOL_DEFINITION"
#endif

Which works fine in this case:

#include "stdio.h"
#include "pre.h"
#include "pre.h"
#include "pre.h"
//const char *pCompileError = mysymbol;
#include "post.h"
//const char *pCompileError = mysymbol;
#include "post.h"
//const char *pCompileError = mysymbol;
#include "post.h"

int main(void)
{
    const char *p = mysymbol;
    printf("%s\n", p);
    return 0;
}

Edit: Works fine with gcc 4.0.

This doesn't actually work -- the symbol is defined after the first inclusion of post.h. Please try and see.
David Citron
Numerical evalutaion in the preprocessor is somehwat old. Otherwise there wouln't be any need for "#if" only for "#ifdef". I have seen code like "#if DEFINEDVALUE >= 2" quite often. Maybe a bug in your gcc version?
@nusi -- what I mean is that if you have "#define A 1" and "#define B (A+1)" this will NOT result in B==2 as required in the code above.
David Citron
"#define A 1, #define B (A+1), #if B == 2, #error foo, #endif" works with gcc4. But you are right, the code in my answer seems to be flawed.
@nusi -- yeah, you're right, the simple case works. But passing the value through a "temp" does not work. Any ideas?
David Citron