17

Do I need an extern "C" {} block to include standard C headers in a C++ program. Only consider standard C headers which do not have counterparts in C++.

For example:

extern "C" {
 #include <fcntl.h>
 #include <unistd.h>
}
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Martin
  • 9,089
  • 11
  • 52
  • 87
  • Just found this question that's similar to yours: [Why do we need extern “C”{ #include } in C++?](http://stackoverflow.com/questions/67894/why-do-we-need-extern-c-include-foo-h-in-c) – AusCBloke Nov 10 '11 at 23:00

7 Answers7

23

The system C headers usually already include a extern "C" block, guarded by #ifdef __cplusplus. This way the functions automatically get declared as extern "C" when compiled as C++ and you don't need to do that manually.

For example on my system unistd.h and fcntl.h start with __BEGIN_DECLS and end with __END_DECLS, which are macros defined in sys/cdefs.h:

/* C++ needs to know that types and declarations are C, not C++.  */
#ifdef   __cplusplus
# define __BEGIN_DECLS  extern "C" {                                            
# define __END_DECLS }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif
sth
  • 222,467
  • 53
  • 283
  • 367
10

The behavior of <fcntl.h> and <unistd.h> in C++ is not specified by the standard (because they are also not part of the C89 standard). That said, I have never seen a platform where they (a) exist and (b) actually need to be wrapped in an extern "C" block.

The behavior of <stdio.h>, <math.h>, and the other standard C headers is specified by section D.5 of the C++03 standard. They do not require an extern "C" wrapper block, and they dump their symbols into the global namespace. However, everything in Annex D is "deprecated".

The canonical C++ form of those headers is <cstdio>, <cmath>, etc., and they are specified by section 17.4.1.2 (3) of the C++ standard, which says:

<cassert> <ciso646> <csetjmp> <cstdio> <ctime> <cctype> <climits>
<csignal> <cstdlib> <cwchar> <cerrno> <clocale> <cstdarg> <cstring>
<cwctype>

Except as noted in clauses 18 through 27, the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in ISO/IEC 9899:1990 Programming Languages C (Clause 7), or ISO/IEC:1990 Programming Languages—C AMENDMENT 1: C Integrity, (Clause 7), as appropriate, as if by inclusion. In the C++ Standard Library, however, the declarations and definitions (except for names which are defined as macros in C) are within namespace scope (3.3.5) of the namespace std.

So the standard, non-deprecated, canonical way to use (e.g.) printf in C++ is to #include <cstdio> and then invoke std::printf.

Nemo
  • 70,042
  • 10
  • 116
  • 153
3

Yes, you do. However, many systems (notably Linux) are already adding an extern "C" bracketing like you do. See (on Linux) files /usr/include/unistd.h /usr/include/features.h and the macro __BEGIN_DECLS defined in /usr/include/sys/cdefs.h and used in many Linux system include files.

So on Linux, you usually can avoid your extern "C" but it does not harm (and, IMHO, improve readability in that case).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • "does not harm"? But I was told "You shouldn't even need to do that (the extra extern "C" {}) in most cases as they are system headers. You can actually break things doing that as some have C++ only exports". Is that true? I just asked a question here [Are most linux system headers C++ compatiable?](https://stackoverflow.com/questions/58417324/are-most-linux-system-headers-c-compatiable) – Rick Oct 16 '19 at 16:24
1

No, you should use the C++ wrapper headers (for instance like <cstdio>). Those take care of all that for you.

If it's a header that doesn't have those, then yes, you'll want to wrap them in extern "C" {}.

ETA: It's worth noting that many implementations will include the wrapper inside the .h file like below, so that you can get away with not doing it yourself.

#ifdef  __cplusplus
extern "C" {
#endif

#ifdef  __cplusplus
}
#endif
Rob K
  • 8,757
  • 2
  • 32
  • 36
  • Worth noting that the `` etc. headers technically put their definitions in the `std` namespace. (Many implementations also put them in the top-level namespace, but that is not what the standard says.) – Nemo Nov 10 '11 at 23:14
0

the macro __BEGIN_DECLS defined in /usr/include/sys/cdefs.h and used in many Linux system include files.

enter image description here

jamlee
  • 1,234
  • 1
  • 13
  • 26
-1

It is a good idea to let the compiler know so that it can expect C code when compiling as C++. You might also find that the header files themselves contain extern "C" { as guards.

For example, curses.h on my system contains:

#ifdef __cplusplus
extern "C" {
...
AusCBloke
  • 18,014
  • 6
  • 40
  • 44
  • 2
    *"let the compiler know so that it can expect C code when compiling as C++"* - That's not what `extern "C"` does. It doesn't change the interpretation of code. It doesn't even apply to code. It's a language linkage directive that instructs the compiler to generate symbols compatible with those the linker expects for C. It makes C++ code callable from C, but doesn't change code generation. – IInspectable Sep 07 '16 at 08:50
  • @IInspectable Doesn't _"instructs the compiler to generate symbols compatible with those the linker expects for C"_ imply that it applies to code, or at least the calling convention of code? It is definitely letting the compiler (as well as the linker) know something. – Tanz87 Apr 14 '17 at 14:12
  • @Tanz87: It doesn't change code generation one bit. The generated object code is identical with or without `extern "C"`. The directive applies to symbol naming only. It has no bearing on calling conventions. – IInspectable Apr 14 '17 at 17:56
-1

I just double checked the stdlib.h for the GNU compiler and the declarations do not use extern "C" as declarations.

edit:

if defined __cplusplus && defined _GLIBCPP_USE_NAMESPACES
define __BEGIN_NAMESPACE_STD    namespace std {

So including the old headers will place declarations on std provided _GLIBCPP_USE_NAMESPACES is defined?

strager
  • 88,763
  • 26
  • 134
  • 176
Ian Haggerty
  • 1,741
  • 16
  • 22