tags:

views:

360

answers:

3

Background:

Let assume that I have two header files a.h and b.h.

a.h contains:

#define VAR 1

b.h contains:

#define VAR 2

Note: The name of both of the macro is same. Let say I have some file myFile.c which includes both of the header files i.e. a.h and b.h.

When I try to access VAR, I get a redefinition error of VAR.

In order to resolve this problem, I inserted #ifndef VAR statement in both a.h and b.h files to prevent this error. a.h file becomes

#ifndef VAR
  #define VAR 1
#endif

b.h file becomes

#ifndef VAR
  #define VAR 2
#endif

Note: The header file can contain multiple macros, not just one macro.

Problem:

Let's assume that a.h and b.h files are obtained from third party library. These files don't contain #ifndef VAR statement.

I am not allowed to change their header files.

Can I resolve macro 'VAR' redefinition error in myFile.c or myFile.cpp file which uses VAR macro?

I know I #undef VAR can be used to undefine a macro VAR. How can I selectively include VAR later in my program? i.e. on line 10 of myFile.c code I should be able to refer to VAR definition from a.h file, on line 15 of my code I should be able to refer to VAR from b.h file and on line 18 again I should be able to refer to VAR from a.h file.

In short, am I able to do macro polymorphism ? Given a name of header file, it should refer to macro definition present in that file.

I thought of using namespace trick to resolve an issue. Define first header file in namespace first and second header file in namespace second.

I tried defining two namespaces. First namespace contains #include a.h and second namespace contains b.h. However, namespace trick does not work with macro. When I tried to access firstns::VAR, compiler reports an error message.

Can you please suggest some way?

+2  A: 

You could include the problematic header files always via your own dedicated header files, where you can add the necessary #ifdef, #undef etc. macros to prevent redefinition errors. E.g.

wrapperToA.h
-----
#ifdef VAR
  #undef VAR
#endif

#include "a.h"

Update: @Vlad worked out the full solution in the meantime - kudos to him (and +1 :-)

Péter Török
This does not answer the OPs need to interchangeably use either `A` or `B`'s definition of `VAR`.
vladr
+5  A: 

Macro expansion happens at the preprocessor level and is impervious to namespace use.

Are all macros that you want to use simple constants, not used in token concatenation etc.?

If so, then you can try something like the following to bridge the preprocessor/compiler gap and retain access to both the A and B definitions of VAR etc., if it suits your situation:

// ab_wrapper.h
#include <a.h>
static const int   A_VAR1 = VAR1;
static const char* A_VAR2 = VAR2;
#undef VAR1
#undef VAR2

#include <b.h>
static const int   B_VAR1 = VAR1;
static const char* B_VAR2 = VAR2;

// code.c
#include <ab_wrapper.h>
...
int x = A_VAR1;
int y = B_VAR1;
...

Cheers, V.

vladr
It works for macros which defines constant. What to do for macros which computes some values ? Can we write inline functions for such macros and then undef those macros ?
@user310119, yes, exactly.
vladr
A: 

To extend on Peter Torok's answer.

It is generally a good idea to wrap 3rd party components.

There are multiple steps:

  • wrapping the headers in your own headers, which allows to control options (for example defining some preprocessing tokens or undefining others based on your own tokens)
  • creating a lightweight facade library that takes care to hide potentially dangerous methods, wrap them with mutexes if necessary etc... and otherwise simply hide the details so that any change does not ripple throughout all your code base.

You are more interested in the first statement, which is also the most common. Just wrap them:

// wrapper/a.h
#ifdef VAR
#undef VAR
#endif // ifdef VAR

#include <3rdparty/a.h>

If you systematically wrap all your dependencies this way, you won't have any problem tweaking afterward since you can modify your own wrapper headers and just recompile the application without intervening explicitly in the 3rd party headers (which is NEVER recommended).

There is however a question of effect that you should carefully review...

// 3rdparty/a.h
#define VAR 1

// 3rdparty/aa.h
#include "a.h"
typedef int IntArray[VAR];

// 3rdparty2/b.h
#define VAR 2

This is definitely more complicated :) You also need to wrap "aa.h" with the undef to avoid the issue...

And of course, it means you'd better not rely on VAR yourself anywhere in your code since you know its definition might change depending the order in which you include the headers...

Matthieu M.