Michael
Michael

Reputation: 7809

How to "disable" macros imported from C-Header

Class A uses a library written in C. This library provides some data types and constants which are used in A. Unfortunately, the library also defines macros in its header file, which collide with my C++ code in main.cpp or in other classes using A.

How can I prevent macros of c_library.h being executed when A.h is included somewhere? I would also be open for architectural changes, but I would prefer not to touch the C library.

Of course, there's the #undef directive. But this would mean a lot of manual work for every macro or for every collision. (Ok, there are not too many - but hey, this must be possible more elegant?)

Code:

//main.cpp

#include "A.h"

...
A a(...)
...
std::max(x, y); // oops, problem since max is defined as macro in c_library.h
...

//A.h
#include "c_library.h"

class A{
public:
    A(...);
    static void callbackForCLibrary(datatypeOfCLibrary d){...}
private:
    private datatypeOfCLibrary1;
    private datatypeOfCLibrary2;
}

Upvotes: 14

Views: 3770

Answers (6)

stux
stux

Reputation: 2976

Another approach is to add a new macro switch to the troublesome file "DO_NOT_DEFINE_MACROS"

Modify the troublesome file to NOT define macros if that macro is defined,

Then before you include it, define the macro, include the file, then undef the macro.

Upvotes: 0

Alex Celeste
Alex Celeste

Reputation: 13370

Potentially (not sure how well this will work in practice) #undef doesn't have to mean manual work - you could auto-generate a second file to include that #undefs all of the definitions from the first header.

e.g. given this header:

#define A(X, Y) [X ; Y]
#define B(X, Y) {X...Y}
#define C this is C
#define D this is D

...run the following short script:

gcc -undef -dN -E foo.h > undef_foo.h
sed -i ".bak" 's/#define[ \t]\([A-Za-z0-9_]*\)/#undef \1/g' undef_foo.h
gcc -undef -dD -E - < /dev/null >> undef_foo.h
sed -i ".bak" '/#[du]/!d' undef_foo.h

...to produce this counter-header:

#undef __STDC__
#undef __STDC_HOSTED__
#undef __DYNAMIC__
#undef A
#undef B
#undef C
#undef D
#define __STDC__ 1
#define __STDC_HOSTED__ 1
#define __DYNAMIC__ 1

The basic idea: get a list of all definitions that are a consequence of including foo.h. The -undef -dN parameters to GCC minimize the amount of system-provided stuff that will be included in this list (down to three for me, not sure how consistent this is), to minimize the collateral and simplify the output. Then replace all #define lines with equivalent #undef lines (-dN makes this easier by not listing the replacements). Then append whatever few system-defined macros GCC still included to the end of the file, so their values are restored. Finally, remove all directives from the file that are not #define or #undef.

Usage:

#include "foo.h"
#include "undef_foo.h"

A(1, 2)
B(3, 4)
C
D

Run through gcc -E and observe the macros not expanding.

Someone with better scripting skills can probably make this a lot better, but that's the basic idea.

Upvotes: 8

Rob K
Rob K

Reputation: 8926

You could create a "wrap_c_library.h" which is something like:

#ifndef WRAP_C_LIBRARY_H
#define WRAP_C_LIBRARY_H

#include "c_library.h"

#undef TROUBLESOME_MACRO_FROM_C_LIBRARY

#endif // WRAP_C_LIBRARY_H

Upvotes: 10

paulsm4
paulsm4

Reputation: 121649

1) For any specific macro, you can "disable" it with #undef.

2) If you don't want ANY definitions from a particular header: just don't #include it.

3) If the header is being implicitly included from something else, and you still want to "disable" the entire header, then you can #define the header guard before your first inclusion.

4) I can't imagine any of these options would apply to "std::max()":

http://en.cppreference.com/w/cpp/algorithm/max

Upvotes: 5

Mark B
Mark B

Reputation: 96241

You already know about the #undef option, which would do what you need.

There is another option however. You could completely hide the fact that your A uses library C from your users: Define your own types and interface in the header and class definition of A and remove the library include from your A header. Then in your implementation file you can include the library header and utilize the library in whatever manner is needed, all the while hiding the include of the c_library.h from your users. This has the added advantage of reducing the coupling between your class users, your class, and the library that it depends on.

Upvotes: 18

Jason
Jason

Reputation: 32510

You could use the #ifdef and #undef preprocessor directives to detect the functions you want to call in C++, and disable the colliding macros declared in the C-header

Upvotes: 6

Related Questions