I'm writing a C library, which may potentially be useful to people writing C . It has a header which looks like this:
#ifndef FOO_H_
#define FOO_H_
#include <bar.h>
#include <stdarg.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void foo_func();
#ifdef __cplusplus
}
#endif
#endif
and I was wondering - should I move the extern "C"
bit before including the header include directives? Especially seeing how, in practice, some of those headers might themselves have an extern "C"
?
CodePudding user response:
No, in general you shouldn't move it to include the headers.
extern "C"
is used to indicate that the functions is using the C calling convention. The declaration has no effect on variables, #define
s or other includes (unless you're including a C library without C support in a C file).
Without the declaration, when compiling using a C compiler, the function is assumed to follow the C convention, and when compiling using a C compiler, the C convention is assumed. In case the same header file is used for C and C code, you would get a linker error, since the compiled function has different names in C and C .
Although it's possible to put all your code between the #ifdef blocks, I personally don't like it, because it's really only intended for the function prototypes, and I frequently see people copy-pasting this at places where it shouldn't be. The cleanest way is to keep it where it's supposed to be, which is around the function prototypes in a C/C header file.
So, to answer your question "should I move the extern "C"
bit before including the header include directives?", my answer is: No, you shouldn't.
But is it possible? Yes, and it probably won't break anything, but it's not needed.
There is one exception when you really need it: when a C library does not contain these constructs and you want to use that library in a C project, you could wrap the include with extern "C"
.
CodePudding user response:
Surprisingly yes. After reading the standard now even I would write
#ifndef FOO_H_
#define FOO_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <bar.h>
#include <stdarg.h>
#include <stddef.h>
void foo_func();
#ifdef __cplusplus
}
#endif
#endif
For 2 reasonss:
1 Having nested extern "C"
are no problem, so your bar.h
include would be fine. Like this it looks clearer and more important
2 To be really portable your surprisingly have to wrap an extern "C"
around your C headers for C users, if they don't want to.
Because I just looked thru the C Standard and 16.5.2.3 Linkage [using.linkage] states
Whether a name from the C standard library declared with external linkage has extern "C" or extern "C " linkage is implementation-defined. It is recommended that an implementation use extern "C " linkage for this purpose.1
To be safe than sorry, you indeed should wrap an extern "C"
around those includes but, you should not have to, since this implies to the headers in D.9 C headers [depr.c.headers] like <stdlib.h>
which you are using.
CodePudding user response:
This is covered in the C FAQ.
First, How to include a standard C header file in C code? Nothing special is needed, as standard C header files work seamlessly with C . So you don't need to wrap stdarg.h
and stddef.h
in extern "C"
.
Then, for non-standard C headers, there are two possibilities: either you can’t change the header, or you can change the header.
When you can't change the C header, wrap the #include
in extern "C"
.
// This is C code
extern "C" {
// Get declaration for f(int i, char c, float x)
#include "my-C-code.h"
}
int main()
{
f(7, 'x', 3.14); // Note: nothing unusual in the call
// ...
}
When you can change the header, edit it to conditionally include extern "C"
in the header itself:
#ifdef __cplusplus
extern "C" {
#endif
. . .
#ifdef __cplusplus
}
#endif
In your case it comes down to whether you have control over the contents of bar.h
. If it's your header, then you should modify it to include extern "C"
and not wrap the #include
itself.
Headers should work the same way regardless of how/when/where they are included. Wrapping an #include
in extern "C"
, #pragma pack
, special #define
s, etc, should be reserved for last resort workarounds, as this may interfere with how the header behaves in different scenarios, reducing the system's maintainability in the long run.
As StoryTeller said in the comments:
Some headers are explicitly written under the assumption that the outermost "scope" has C language linkage. They may use
__cplusplus
to remove template declarations, and if you wrap them up like you wish to, your header will be fundamentally broken. So as mentioned already, make your declarations correct, and let other headers do their thing unimpeded. Even standard library headers may break (since an implementer may reason its going to be shared anyway, and then do some expert friendly things inside).
Note that standard C headers may be implemented using C linkage, but may also be implemented using C linkage. In which case wrapping them in extern "C"
might result in link errors.