How can I include a C header that uses a C++ keyword as an identifier in C++?

C++CClang

C++ Problem Overview


I've been using C++ and compiling with clang++. I would like to include the header for an X11 program I am writing.

Unfortunately this header uses explicit for some field names (such as line 727) and that is a keyword in C++.

Is there anyway to deal with this?

xcb/xkb.h:

// ...

#ifdef __cplusplus
extern "C" {
#endif

// ...

typedef struct xcb_xkb_set_explicit_t {
    xcb_keycode_t keycode;
    uint8_t       explicit;
} xcb_xkb_set_explicit_t;

// ...

#ifdef __cplusplus
}
#endif

// ...

C++ Solutions


Solution 1 - C++

Use a macro to rename the fields:

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wkeyword-macro"
#endif
#define explicit explicit_
#ifdef __clang__
#pragma clang diagnostic pop
#endif

#include <xcb/xkb.h>

#undef explicit

Using a keyword as a macro name is ill-formed in standard C++, but GCC, Clang (with pragma), and MSVC do accept it. (The standard says you "shall not" do it, cppreference clarifies that it means "ill-formed".)

Solution 2 - C++

> How can I include a C header that uses a C++ keyword as an identifier in C++?

There is no standard-conforming solution to be able to include such header. In order to be able to include a header in C++, it must be written in valid C++. In case of a C header, it would thus have to be written in common subset of C and C++.

The ideal solution is to fix the header to be valid C++. A standard-conforming workaround is to write a C++ conforming wrapper in C.

Solution 3 - C++

(Not an answer to the exact question, but possibly useful for the general problem of interfacing C & C++)

How about using an intermediate set of C files (.c & .h) to wrap the incompatible header and provide a C++-compatible interface to the rest of your program? If that interface is high-level enough, then you would only need to include the incompatible header file in the wrapper .c file only, allowing the wrapper .h header file to be included in C++ code normally.

Depending on the details, you might end up doing some trivial copying of data, but the resulting C interface might be much more suited to your specific needs.

Solution 4 - C++

One solution is to add a generation step to your makefile that copies the header and renames the field, and include said autogenerated header instead.

(This is between difficult to impossible to do in the general case, but in this case given that the header isn't likely using explicit for anything else even just a simple (gnu) sed (s/\bexplicit\b/explicit_field/g or somesuch) would work. The trickier bit is figuring out the correct file to copy.)

Make sure that the location of the copied header is before the original header in your include path, in case something else in your includes indirectly includes the header.

Just changing a field name shouldn't have any effects on e.g. ABI, at least for a nominally-C-compatible header. (There are cases in C++ where renaming a field does affect things.)

Categories

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCLearnerView Question on Stackoverflow
Solution 1 - C++HolyBlackCatView Answer on Stackoverflow
Solution 2 - C++eerorikaView Answer on Stackoverflow
Solution 3 - C++thkalaView Answer on Stackoverflow
Solution 4 - C++TLWView Answer on Stackoverflow