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>
}
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>
}
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
.
<fcntl.h>
and <unistd.h>
is specified by the POSIX standard -- POSIX requires that these header files be usable directly by the supported C or C++ compiler without anything additional -- so essentially, they're required to have a embedded, guarded extern "C"
or something else equivalent for all supported compilers. –
Brieta 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
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
.
<fcntl.h>
and <unistd.h>
is specified by the POSIX standard -- POSIX requires that these header files be usable directly by the supported C or C++ compiler without anything additional -- so essentially, they're required to have a embedded, guarded extern "C"
or something else equivalent for all supported compilers. –
Brieta 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).
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
<cstdio>
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.) –
Licketysplit the macro __BEGIN_DECLS defined in /usr/include/sys/cdefs.h and used in many Linux system include files.
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" {
...
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. –
Woodward extern "C"
. The directive applies to symbol naming only. It has no bearing on calling conventions. –
Woodward 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?
© 2022 - 2024 — McMap. All rights reserved.