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 and #define
s, so there is no need to include these. If an #include
is inside an extern "C"
block, this effectively modifies the function declarations inside that header file!
Background: Without the extern "C"
declaration, when compiling using a C compiler, a 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 in many cases this won't break anything. Sometimes it is even necessary, if the function prototypes in an external header file are incorrect (e.g. when they are C functions and you want to call them from C++) and you cannot change that library.
However, there are also cases where doing so breaks the build. Here's a simple example that fails to compile if you wrap the include using extern "C"
:
foo.h:
#pragma once
// UNCOMMENTING THIS BREAKS THE BUILD!
//#ifdef __cplusplus
//extern "C" {
//#endif
#include "bar.h"
bar_status_t foo(void);
//#ifdef __cplusplus
//}
//#endif
foo.c:
#include <stdio.h>
#include "foo.h"
#include "bar.h"
bar_status_t foo(void)
{
printf("In foo. Calling bar wrapper.\n");
return bar_wrapper();
}
bar.h:
#pragma once
typedef enum {
BAR_OK,
BAR_GENERIC_ERROR,
BAR_OUT_OF_BEAR,
// ...
} bar_status_t;
extern "C" bar_status_t bar_wrapper(void);
bar_status_t bar(void);
bar.cpp:
#include <iostream>
#include "bar.h"
extern "C" bar_status_t bar_wrapper(void)
{
std::cout << "In C/C++ wrapper." << std::endl;
return bar();
}
bar_status_t bar(void)
{
std::cout << "In bar. One bear please." << std::endl;
return BAR_OK;
}
main.cpp:
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
#include "bar.h"
int main(void)
{
bar_status_t status1 = foo();
bar_status_t status2 = bar();
return (status1 != BAR_OK) || ((status2 != BAR_OK));
}
When uncommenting the blocks in a.h, I get the following error:
main2.cpp:(.text+0x18): undefined reference to `bar'
collect2.exe: error: ld returned 1 exit status
Makefile:7: recipe for target 'app2' failed
Without, it builds fine. A C main calling only C functions from foo and bar will build fine either way, since it's unaffected by the #ifdef __cplusplus
blocks.