DMan
DMan

Reputation: 429

Preprocessor definition duplication

I have two libraries and unfortunately they define two identical preprocessor definitions (which I need to use):

lib1.h

#define MYINT 1

lib2.h

#define MYINT 2

In my program I need to use both of them:

#include <Lib1.h>
#include <lib2.h>
...
int myint = MYINT;

And here I have error that MYINT can't be resolved.

How can I solve that when I cannot modify the lib files?

Upvotes: 6

Views: 1139

Answers (4)

Richard Chambers
Richard Chambers

Reputation: 17573

The approach I would take is to derive from each of the include files an extended version of the include files which will provide the MYINT through a different mechanism outside of the include files themselves.

So create an include file from lib1.h named lib1_ext.h containing the following lines:

#if !defined(MYLIB1_EXT_H_INCLUDED)
#define MYLIB1_EXT_H_INCLUDED
// ensure that MYINT is not defined no matter what order the include files are used
#undef MYINT
#include "lib1.h"
const int myInt_lib1 = MYINT;  // make a copy of the value of MYINT if it is needed
// make sure MYINT is undefined to allow the compiler to catch any dependencies on it
#undef MYINT
#endif

and similarly for lib2.h create lib2_ext.h as in:

#if !defined(MYLIB2_EXT_H_INCLUDED)
#define MYLIB2_EXT_H_INCLUDED
// ensure that MYINT is not defined no matter what order the include files are used
#undef MYINT
#include "lib2.h"
const int myInt_lib2 = MYINT;  // make a copy of the value of MYINT if it is needed
// make sure MYINT is undefined to allow the compiler to catch any dependencies on it
#undef MYINT
#endif

now when using any of the functionality of the library use the respective copy of the MYINT value, myInt_lib1 when using lib1.h functionality and/or myInt_lib2 when using lib2.h functionality. However if MYINT is only used with the library header file itself and is not needed anywhere to actually use the library then you can just discard that statement.

See as well Can I redefine a C++ macro then define it back? which shows how to save and restore a macro definition with some vendors' compilers and the pragma directive. It doesn't look like that is really applicable with your posting however.

That posting also has an answer which describes the basics of macro expansion and why the const int myInt_lib1 = MYINT; is needed to save the value of MYINT rather than using the Preprocessor as in #define MYINT_LIB1 MYINT to save the value of MYINT. The Preprocessor delays the expansion of a macro as long as possible and the result is that trying to use a Preprocessor macro as in #define MYINT_LIB1 MYINT to save the value of MYINT doesn't work once MYINT is undefined using the #undef directive. When the Preprocessor first replaces the text MYINT_LIB1 with the text MYINT and then does a rescan, since MYINT is now undefined, the text MYINT remains and the result is a compiler error if you are lucky.

One thing to consider with this work around

This work around assumes that all that is needed is the numerical value of MYINT which is treated as an int constant value. So it assumes that the places where MYINT is used are places where a const int can also be used.

This means that any kind of token pasting, #if test or other Preprocessor action that involves treating the text which MYINT is defined as text that can be used by the Preprocessor for other macro operations is not going to work properly outside of the places where the lib.h or lib2.h are included and processed by the Preprocessor.

It also means that you can not specify a compiler option to declare MYINT as a part of conditional compilation since the macro created by the compiler option is going to be ignored and eliminated by this work around.

So any dependency that the source generated by the Preprocessor has on MYINT as a text macro outside of each of the include files will cause the compile to break.

An example of a possible dependency would be a macro within lib1.h which uses MYINT to create an additional, unseen argument to a function as in:

int funcStuff (int a, struct b *pBthing);

#define FUNCSTUFF (pBthing)  funcStuff(MYINT, (pBthing))

with the expectation that anybody using the library would use FUNCSTUFF(&bThing); rather than funcStuff (MYINT, &bThing);. To make this work you would need to either use the function funcStuff() directly as in funcStuff(myInt_lib1, &bThing); or make your own version of the FUNCSTUFF() macro that uses myInt_lib1 rather than MYINT.

Upvotes: 1

eugenioperez
eugenioperez

Reputation: 737

With no preprocessor tricks:

lib1_handler.h

extern int lib1_handler_myint;
// or
int lib1_handler_myint_f();

lib1_handler.c

#include <Lib1.h>

int lib1_handler_myint = MYINT;
// or
int lib1_handler_myint_f() { return MYINT; }

lib2_handler.h

extern int lib2_handler_myint;
// or
int lib1_handler_myint_f();

lib2_handler.c

#include <Lib2.h>

int lib2_handler_myint = MYINT;
// or
int lib2_handler_myint_f() { return MYINT; }

main.c

#include "lib1_handler.h"
#include "lib2_handler.h"

int void () {
  return lib1_handler_myint || lib2_handler_myint_f();
}

Upvotes: 0

Blaze
Blaze

Reputation: 16876

Get the MYINT value of the first library before the second one replaces it.

#include <Lib1.h>
int myInt1 = MYINT;
#undef MYINT
#include <lib2.h>
int myInt2 = MYINT;
#undef MYINT

Of course, that doesn't work if MYINT is something dynamic and you need to keep its actual content around.

Edited by handy999: no semicolon at the end of preprocessor statements.

Upvotes: 3

Jarod42
Jarod42

Reputation: 217245

You might #undef MYINT before to include the header as workaround.

#undef MYINT
#include <Lib1.h>
const int myint_lib1 = MYINT; // 1

#undef MYINT
#include <lib2.h>
const int myint_lib2 = MYINT; // 2

Upvotes: 5

Related Questions