13

Possible Duplicate:
How to check (via the preprocessor) if a C source file is being compiled as C++ code

I'm trying to find a standard macro which will test whether a header file is being compiled as C or as C++. The purpose of this is that the header may be included by either C or C++ code, and must behave slightly differently depending on which. Specifically:

In C, I need this to be the code:

extern size_t insert (const char*);

In C++, I need this to be the code:

extern "C" size_t insert (const char*);

Additionally, is there a way to avoid putting #ifdef's around every declaration in the header?

Community
  • 1
  • 1
Talia
  • 1,400
  • 2
  • 10
  • 33
  • 1
    I may be biased, but I would argue that this question additionally has to do with extern. Since I had not known about the "extern { ... }" syntax previously, my selected answer is much more helpful than the one given in your proposed duplicate. I will edit the question to show this difference. – Talia Sep 23 '12 at 03:32
  • I've left an x-ref to this question on the proposed duplicate. You could improve the distinction between the two by a revised title such as 'How to conditionally define `extern "C"` or just `extern` auto-detecting the C or C++ compiler?" or something along those general lines. – Jonathan Leffler Sep 23 '12 at 06:51
  • @JonathanLeffler I've edited the title to reflect what (I think) is really being asked, as illustrated by the example in the text. ... searching for this did, however, reveal a duplicate title: http://stackoverflow.com/questions/8742534/including-c-header-in-c-file ... but not duplicate content. – Jim Balter Sep 23 '12 at 20:23
  • @JonathanLeffler I also found http://stackoverflow.com/questions/11712707/extern-functions-in-c-vs-c in which you gave a lengthy answer that covers the question here, under "Issue 2: Inter-working between C and C++". – Jim Balter Sep 23 '12 at 20:34

3 Answers3

27

It is normal to bracket C header files as follows so they can be used in C++ programs. Check your system header files such as stdio.h and you will probably see this:

#ifdef __cplusplus
extern "C" {
#endif

...

#ifdef __cplusplus
}
#endif
Jim Balter
  • 16,163
  • 3
  • 43
  • 66
15

The answer is to use the macro __cplusplus. In this instance, the most straightforward approach is:

extern
#ifdef __cplusplus
"C"
#endif
size_t insert (const char*);

This macro is part of the C++ standard.

Talia
  • 1,400
  • 2
  • 10
  • 33
  • 4
    And if you want to do this for multiple functions, the norm is `#ifdef __cplusplus extern "C" { #endif` ... `#ifdef __cplusplus } #endif`. – chris Sep 22 '12 at 23:28
  • 4
    Another possibility: `#ifdef __cplusplus` ... `#define EXTERN extern "C"` ... `#else` ... `#define EXTERN extern` ... `#endif` (where ... denotes a newline) – Keith Thompson Sep 22 '12 at 23:45
  • g++ does not like #define EXTERN extern "C" it wines so: error: expected unqualified-id before string constant – QT-1 Dec 21 '16 at 00:11
7

You might find it reasonable to define three macros to help with this:

#ifdef __cplusplus
#define EXTERN_C_BEGIN extern "C" {
#define EXTERN_C_END   }
#define EXTERN_C       extern "C"
#else
#define EXTERN_C_BEGIN /* Nothing */
#define EXTERN_C_END   /* Nothing */
#define EXTERN_C       extern /* Or Nothing */
#endif /* __cplusplus */

This would be most useful in a standard header that's included in most places in your project. For a single function, you might write:

EXTERN_C size_t insert(const char *name);

For a group of functions, you might write:

EXTERN_C_BEGIN

size_t other_insert(const char *name);
size_t other_delete(const char *name);
size_t other_update(const char *old_name, const char *new_name);

EXTERN_C_END

It is permissible to include extern in front of the individual functions inside the EXTERN_C_BEGIN to EXTERN_C_END block.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278