Can I mimic a C header that redefines bool in C++?
Asked Answered
S

5

55

I am writing a program and I would really prefer to write in C++, however, I'm required to include a C header that redefines bool:

# define false 0
# define true  1
typedef int bool;

The obvious solution would be to edit the header to say:

#ifndef __cplusplus
# define false 0
# define true  1
typedef int bool;
#endif

but, alas, since the library is read-only I cannot.

Is there a way I can tell gcc to ignore this typedef? Or, can I write most functions in C++ and then make a C wrapper for the two? Or, should I suck it up and write the thing in C?

Sascha answered 23/2, 2014 at 9:4 Comment(5)
If that's <stdbool.h>, you can just #define the appropriate tag it has to say it's already done its work. If it's like C, __bool_true_false_are_definedKayo
@Kayo <stdbool.h> should have its own c++ guards alreadyDistrict
May be this will have something useful: #19378178Satellite
@Erbureth, But you wouldn't want it happening even once.Kayo
@Kayo I meant c++ guards, not standard include guardsDistrict
P
75

You can hack it!

The library, call it fooLib, thinks it's using some type bool which it has the prerogative to define. To the library, bool is just an identifier.

So, you can just force it to use another identifier instead:

#define bool fooLib_bool
#include "fooLib.h"
#undef bool
#undef true
#undef false

Now the compiler sees the offending line transformed to this:

typedef int fooLib_bool;

You're stuck with the interface using type fooLib_bool = int instead of a real bool, but that's impossible to work around, as the code might in fact rely on the properties of int, and library binary would have been compiled with such an assumption baked in.

Pessa answered 23/2, 2014 at 9:36 Comment(7)
That might not be a problem, as the library binary will see int anyway and you will need to provide an in at the interface level (or bool will be casted to it)District
Strictly speaking, #define <keyword> ... is forbidden. I suppose most C++ compilers will accept it, but they would be within their rights to refuse to compile the program.Loria
@MatthieuM., Only if you include a standard library header. I'm not too sure how that would apply if the macro's there and gone all before any headers are included.Kayo
@chris: I hate the C++ Standard. Seriously. I've never read any other document with such intricate definitions and rules. Everytime you find a hard set rule (finally!), it's mitigated by some wording somewhere else. sighLoria
@MatthieuM., I can agree to that. It certainly makes it interesting. I have a feeling its complexity could be comparable to the laws we live by.Kayo
@chris: Of course, you may have a problem if the library header includes standard libraries....Gel
@Hurkyl The library header is guaranteed to be C-only, and although the C standard library headers are tangentially referenced in the C++ spec, I think the intent is that the C-language rules should apply to them.Pessa
S
26

I suppose you can wrap the offending code into a header and then undef what you don't need

Library_wrapper.h:

#define bool something_else // This will get you past the C++ compilation
#include "library.h"
#undef false
#undef true
#undef bool

main.cpp:

#include "Library_wrapper.h" 
#include "boost.h"

Regarding the typedef.. the compiler should complain if you try to redefine a basic type in C++. You can redeclare a type by the way (it is allowed in C++) or define it (simple text replacement).

Spectacle answered 23/2, 2014 at 9:8 Comment(5)
Prolly the typedef and not the #defines that's problematic.Jensen
In C++ you can redefine typedefs, in C you can't so I suppose a workaround as the above would be neededSpectacle
I commented on your original post which didn't include your edit modifying the typedef.Jensen
-1, typedef int int; is not legal. Where did you even get that? It's an invalid combination of type specifiers and no declarator. It doesn't even appear to be a solution, but just duplicates the problem at hand, which is the similarly invalid construct typedef int bool;.Pessa
"In C++ you can redefine typedefs" — you are allowed to repeat a typedef declaration, not to change the meaning. They behave as declarations, not definitions, and it's analogous to declaring a function prototype twice. "C you can't" — the rules are the same in C.Pessa
L
21

Unfortunately, no, you cannot use this file in Standard C++:

§7.1.3 [dcl.typedef]

6/ In a given scope, a typedef specifier shall not be used to redefine the name of any type declared in that scope to refer to a different type.

Thus typedef ... bool; is forbidden.

§17.6.4.3.1 [macro.names]

2/ A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 3, or to the attribute-tokens described in 7.6.

And in §2.12 [lex.key] we find that bool is a keyword.

Thus trying to trick the compiler by using #define bool ... prior to including the offending file is forbidden.


So, what is the alternative ? A shim !

Isolate that offending library behind a C & C++ compatible header of your own; and compile this part as C. Then you can include your own header in the C++ program without issue or tricks.

Note: yes, most compilers will probably accept #define bool ..., but it is still explicitly forbidden by the Standard.

Loria answered 23/2, 2014 at 12:32 Comment(1)
Note: it has been ported to my attention that [macro.names] apparently only applies if you include a Standard Library header within the translation unit.Loria
G
11

You may copy a bad header and use an edited copy. Tell to compiler the path it should prefer and...

Girt answered 23/2, 2014 at 9:17 Comment(2)
Or, just be sure to include the edited copy before the C library and the header guards will take care of the rest. +1Pessa
Oh… but note that the "patched" header may lead to ABI incompatibility with a library. You shouldn't patch the header unless you can recompile the library afterward, or if compilation isn't necessary.Pessa
V
8

You could compile the code which uses the header as C, then just link it together with your C++ object files. You probably use MSVC or GCC; both can compile code as either C++ or C, and will allow you to create compatible object files.

Whether that's a clean solution or unnecessary overkill really depends on the exact situation.

Villose answered 23/2, 2014 at 10:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.