47

I have a C header as part of a C++ library.

This C header would only make sense compiled by a C compiler, or by a C++ compiler within an extern "C" { ... } block, otherwise unresolved link errors would happen.

I thought to add a block such as:

#ifdef __cplusplus
#error "Compiling C bindings with C++ (forgot 'extern \"C\"'?)"
#endif

in the C header, but unfortunately the __cplusplus macro is defined also within an extern "C" { ... } block.

Is there another way to detect this condition correctly?

fferri
  • 18,285
  • 5
  • 46
  • 95

1 Answers1

103

The common practice is not to demand client code wraps your header in extern "C", but to do so conditionally yourself. For instance:

#ifdef __cplusplus
extern "C" {
#endif

  // Header content

#ifdef __cplusplus
}
#endif

That way client code is automatically correct without doing anything beyond including the header.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • I don't know C++ ... Is there any issue with nested `extern "C" { /* ... */ extern "C" { /* ... */ } /* ... */ }` – pmg Mar 11 '19 at 11:14
  • 14
    @pmg - Not in C++. If you nest language linkage specifications, the innermost "wins". The macro is just to prevent a C compiler from rightfully rejecting the `extern "C"`. – StoryTeller - Unslander Monica Mar 11 '19 at 11:15
  • 17
    @Rakete1111 - We shouldn't throw stones from our glass house that has no `restrict` qualifier :P – StoryTeller - Unslander Monica Mar 11 '19 at 12:00
  • @StoryTeller: You mean you haven't thrown right through restrict yet? – Joshua Mar 11 '19 at 15:44
  • Such a shame that C doesn't support extern "C"? This makes zero sense to me. Doesnt the keyword tell C++ to not use name mangling for the C symbols? – Señor CMasMas Mar 11 '19 at 16:09
  • 12
    @SeñorCMasMas - It also tells it to adhere to a C calling convention (those may differ). And the point that was made is that it'd be nice if C compilers didn't reject the syntax outright, but instead treated it as a no-op. So the macro business won't be needed. – StoryTeller - Unslander Monica Mar 11 '19 at 16:21
  • @StoryTeller: Well, the syntax *is* strange. I don't think there is much surprise that C doesn't want to support it. C++ could have adopted a new keyword, e.g. `_C_extern` or something like that, and it would have been easier for C to treat that as a synonym for `extern` (maybe with a macro...), and then support the `extern{}` grouping syntax. – jxh Mar 11 '19 at 22:08
  • @StoryTeller : It would then probably break old code which used it as a function or variable name... – vsz Mar 12 '19 at 06:19
  • names with _Capital are not allowed to use anyway – RiaD Mar 12 '19 at 08:43
  • @RiaD - I don't know to which of my comments you are referring to. I don't believe I touched on reserved identifiers at any point. – StoryTeller - Unslander Monica Mar 12 '19 at 08:53
  • @StoryTeller I believe RiaD was replying to vsz's comment about breaking old code. I'd like to add that one can definitely use identifier with leading underscore and capital, but at their own peril, because doing this produces non-compliant code that may be broken in the future. – joH1 Mar 12 '19 at 09:17
  • 1
    @jxh Language linkage supports more than just `"C"` and `"C++"`; compilers are free to support any toerh language linkage specification. I'd say using a string literal for this is better than introducing a new keyword for each. – Angew is no longer proud of SO Mar 12 '19 at 10:42
  • @Angew: That's an opinion I don't happen to share. An alternative syntax could have involved using a #pragma, that would have been ignored by a C compiler. – jxh Mar 12 '19 at 17:48
  • @RiaD: My suggestion was for the language to make it a standard. – jxh Mar 12 '19 at 17:49
  • as joH1 said my comment was to vsz – RiaD Mar 12 '19 at 18:46