0

After reading Why do we need extern "C"{ #include <foo.h> } in C++? I concluded, including a header within the extern "C"-block is fine.

But I ran into problems with this constellation:

#ifdef __cplusplus
extern "C" {
#endif

#include "mixedstuff.h"

#ifdef __cplusplus
}
#endif

mixedstuff.h:

#ifdef __cplusplus
extern "C" {
#endif

#include "cstuff.h"

#ifdef __cplusplus
}
#include "cppstuff.h"
#endif

As one can see, I ended up with cppstuff.h being included by the C++ compiler within the extern "C" block. This caused a lot of errors, because many statements were just not possible with C-linkage.

The obvious solution is to #include mixedstuff.h outside the extern "C" block. But this requires me to look into each header to see if it is plain C, C++ or mixed.

From this I would recommend to make headers C++ aware, rather than including them in extern "C". Am I right, or is there a better way?

Community
  • 1
  • 1
Sascha
  • 986
  • 10
  • 30
  • The first usage of __cplusplus was unnecessary because the included .h file already takes care of it. Which solves the problem of course. Don't help too much :) – Hans Passant Sep 30 '14 at 15:15
  • That's what I meant with "the obvious solution". I tried to ask for a best-practice for such situations. – Sascha Oct 01 '14 at 07:29

4 Answers4

2

From your description, I gather that mixedstuff.h is designed to be used in both C and C++. Which means that it probably has #ifdef __cplusplus etc., with some pure C++ code in places. In such cases, it should not be included inside an extern "C" block. In general, unless explicitly documented otherwise, most headers should be included at the outermost level, outside all blocks, namespaces, etc. The one exception is pure C headers, where the author has not designed the library to be used from C++; those must be included within an extern "C" block. (But from what I've seen, such headers are becoing rarer and rarer.)

And you shouldn't have to look inside the headers; you need to look at the documentation.

And if you are the author of the header, then you should make it C++ aware (and document this fact, perhaps at the library level).

James Kanze
  • 150,581
  • 18
  • 184
  • 329
1

When the example tells you to put extern "C" in yourself, that is when you are including a C-only header.

As it is C-only, it has been possibly written in C for C and so if you want to use it for C++, you need to specify it to being a C header.

IF you have mixstuff.h it won't work in C as it has C++ only constructs. Those that are C constructs that you want to have with C linkage you should mark explicitly within mixstuff.h. Or isolate them out into their own header.

Note that together with mixstuff.h there will somewhere be a mixstuff.c or mixstuff.cpp being compiled or possibly even two different compilation units. You can us a C++ compiler to compile the implementations, and they can even be C++ (with C linkage) using in their implementations C++ constructs (and often are. You will often give your C++ library a C interface).

If mixstuff was build in C++ originally with C++ name mangling it will not link with your code if you now put extern "C" around its declarations. If the functions really were built by a C compiler though, you need to use extern "C" so you can see them.

CashCow
  • 30,981
  • 5
  • 61
  • 92
1

There are various C and C++ standards, which have commonalities and differences.

If code is written in the common intersection of all your target-standards, just include it in the global namespace.

If it only misses extern "C" when included in C++, wrap it externally.

Otherwise, things get complicated, and you have to patch it directly.

The preprocessor, with conditions on __cplusplus, __STDC_VERSION__ and other feature- and language-test macros, is a way to write code which behaves properly under a wider set of conditions than guaranteed by the general language itself.

Use it wisely, it is easy to misuse.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • +1 for "Use it wisely, it is easy to misuse." I have by now read some about the extern "C"-construct and found no such words of warning. – Sascha Oct 01 '14 at 07:31
1

If you want to ensure stuff has C++ linkage even though the containing header file might be included inside an extern "C" block, you can use an extern "C++" block:

extern "C++" {
#include "cppstuff.h"
}
Chris Dodd
  • 119,907
  • 13
  • 134
  • 226