Question
Do GCC, MSVC, or Clang, or some combination support setting linkage to default to C?
Background
I have a large mixed C/C++ project, and while it's easy and logical to export symbols in the C++ sources with C linkage, those same sources are assuming the stuff in the rest of the project are under C++ linkage.
The current situation requires me to explicitly wrap anything the C sources use that is defined in the C++ sources and everything the C++ sources use from the C sources with extern "C++".
To top things off, I can't put extern "C" around entire source or header files, as the actual C++ stuff will then complain. (Such as from #include <memory> or templates I've defined.)
The standard pattern in a header file is:
#ifdef __cplusplus
// C++ stuff
extern "C" {
#endif
// C/C++ stuff
#ifdef __cplusplus
}
#endif
I'm not sure you've got any other options. The C/C++ stuff must be declared with C linkage everywhere. The C++-specific stuff must be declared with C++ linkage everywhere.
"C" linkage by default makes only sense for C sources, not for C++ sources, and vice versa. "C" linkage usually implies that names/symbols will not be mangled. "C" linkage is not expressive enough to be usable for C++ sources, e.g. for overloaded functions.
Related
Usually to get a C library working from C++ you have to include it with extern "C" { #include <clibrary.h> }. Many libraries will include in their header files code like #ifdef __cplusplus extern "C" { ... to make them more user friendly to C++ code (e.g. pthread.h). Sometimes this is not the case. For instance, stdio.h has no such #ifdef, yet I can still compile & link the usual #include <stdio.h> int main() {printf("Hello");} using a C++ compiler without wrapping it in an extern "C" statement. Why is this?
Usually to get a C library working from C++ you have to include it with extern "C" { #include <clibrary.h> }.
Only when the library was not designed with C++ compatibility in mind. But this is a hack.
Many libraries will include in their header files code like #ifdef __cplusplus extern "C" { ... to make them more user friendly to C++ code (e.g. pthread.h)
Yes, a good library will do this.
As a result, you do not need to and should not add another extern "C" around the #include.
stdio.h is an example of a header that will be doing this properly (see below).
For instance, stdio.h has no such #ifdef
Sure it does! Follow the money trail…
why isn't extern always needed?
So, in conclusion, you only need to do this yourself when the author of the header file didn't do it for you. When the author of the header file did it, you do not need to do it.
For instance, stdio.h has no such #ifdef
It probably does. Regardless, <stdio.h> is a header provided by the C++ standard library (inherited from the C standard library). It is guaranteed to work without extern "C" as are all standard headers.
Note that the usage of <name.h> name of the inherited standard headers in C++ instead of <cname> is deprecated in the current edition of the standard and has been identified as a candidate for removal in future revisions.
why isn't extern always needed?
Simply because some headers have been written to support C++ directly, and so do it by themselves.
c++ compiler could compile code like this, and it executed correctly
#include <stdio.h>
int main() {
printf("test...\n");
return 0;
}
I think printf.c will be compiled to printf.o with c compiler, I just checked the stdio.h, there is no extern "C" keyword, then how could c++ linker link printf in printf.o which is compiled with c compiler?(By the way, my platform is ubuntu 14.04, compiler is gcc 4.8.4)
printf is part of the C++ standard library.
The <stdio.h> header that you include in the C++ source, belongs to the C++ standard library, and is not necessarily the same contents as a C compiler will include.
How the C++ implementation leverages the corresponding C implementation (if at all) is an implementation detail.
When C++ was originally made it was effectively a superset of C. That is to say, you can code perfectly good C in the C++ environment, just by ignoring all of the features that C++ adds. That, and because nowadays most C compilers are C++ compilers in which you can code C, is why you can use printf.
Secondly, no object code is generated for stdio because it is already a library, and so you are linking your own .o code against the already compiled stdio library code, which will be located somewhere in your compilers directory.
Nobody can give you a definitive answer without knowing what implementation you're using.
Cheers and hth. - Alf gave one possibility, which is that the stdio.h that is included by a C++ program may not be the same as the stdio.h that is included by a C program. Another possibility is that it is the same header, and there is an extern "C" block, and you just can't see it. For example, I use gcc, and my /usr/include/stdio.h contains a __BEGIN_DECLS macro, which expands to extern "C" { when compiled as C++. See Do I need an extern "C" block to include standard C headers?
You may not see an explicit extern "C" in stdio.h, but it is there. It's just hiding.
For example, on Linux, in stdio.h we see this:
#include <features.h>
__BEGIN_DECLS
In <features.h> you will find the following:
# ifndef _SYS_CDEFS_H
# include <sys/cdefs.h>
# endif
And in <sys/cdefs.h> you finally see:
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif
So, via a fairly roundabout path, Linux header files have a __BEGIN_DECLS/__END_DECLS wrapper which, when compiled by a C++ compiler, end up wrapping the whole thing inside extern "C".
For a shared library project written in C, if I rewrite part of the code in C++, but exactly the same APIs is kept, will I have any ABI compatibility issues?
If you keep the same API (function names and parameter types) you should be good to go.
What you will need to do is wrap your header files with this (copy & pasted from here):
#ifdef __cplusplus
extern "C" {
#endif
// all of your legacy C code here
#ifdef __cplusplus
}
#endif
This makes sure that the C++ compiler doesn't mangle those names, so the C compiler's extern symbols can still be linked against the exports.
How this works in C or C++?
extern "C" {
#include <unistd.h>
#include <fd_config.h>
#include <ut_trace.h>
#include <sys/stat.h>
#include <sys/types.h>
}
The C++ standard does not specify how compilers should name the symbols in their object files (for instance, Foo::bar() might end up as __clsFoo_fncBar or some gobbledygook). The C standard does, and it is almost always different from how C++ compilers do it (C doesn't have to deal with classes, namespaces, overloading, etc.).
As a result, when you are linking against an object file that was output by a C compiler, you have to tell your C++ compiler to look for symbols with names that correspond to the C standard. You are essentially putting it in "C mode." This is what the "C" part of extern "C" does.
(Alternatively, you might also be declaring functions or variables that could be used by an external C object file. In this case, it means export those symbols the C way.)
If your Project has C and C++ source files and you need to build as a whole( C files calls some functions in C++ files) ,so we need to protect the C file function calls and symbols by declaring as in C++ files by
extern "C"
{
/symbols used in c files/
uint8 GetCurrentthreadState(HANDLE ThreadId)
}
Then the C++ complier generate compilation output which is same as that of C complier for the above declared functions and symbols.So on linking time , the compiler can easily link the C and C++ defined symbols with out any link error.
So my opinion is not needed to give the #ifdef __cplusplus check on compilation.
Because we need to protect the symbols in c++ files right? Also C++ files can be compiled by C++ compiler only right?
/renjith g
It will not work, you need to add the cplusplus preprocessor...
#ifdef __cplusplus
extern "C" {
#endif
// your code
#ifdef __cplusplus
}
#endif
EDIT:
In C++, the name will be treated like in C which mean that there will be no mangle name. It allows to make the difference between two C++ different function with different argument type/number or a different namespace in a library (for library purpose libname.so, libname.a). If the name is mangled, the C program will not be able to recognize it
eg:
int myfction()
void myfunction(int)
void myfunction(int, char)
C library: myfction
C++ library: int_myction (it depend on your compiler)
C++ library: int_myction_int (it depend on your compiler)
C++ library: int_myction_int_char (it depend on your compiler)
// ... which is not allowed in C program
Every C++ Compiler needs to support the extern "C" linkage.
The code in such block could be legacy code written in C for a certain functionality, which is required for the current program.
How this is implemented is mostly compiler dependent, However I heard that many Compilers disable the name mangling and change the calling convention.
I found some code recently where extern "C" was added in source file also for functions. They were also added in the header files where they were declared.
I was under the assumption that adding 'extern "C" in header files was sufficient.
Where should extern "C" blocks be added?
UPDATE:
Suppose I am compiling my C code using a CPP compiler and have added extern "C" guards for all the functions in header files (i.e. all my functions have their prototypes in headers), but in source files I have not added the same. Will this cause a problem?
Since you mean
extern "C" { ... }
style guards, these declare some functions to be of "C" linkage, rather than "C++" linkage (which typically has a bunch of extra name decoration to support things like overloaded functions).
The purpose, of course, is to allow C++ code to interface with C code, which is usually in a library. If the library's headers weren't written with C++ in mind, then they won't include the extern "C" guards for C++.
A C header written with C++ in mind will include something along the lines of
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
to make sure C++ programs see the correct linkage. However, not all libraries were written with C++ in mind, so sometimes you have to do
extern "C" {
#include "myclibrary.h"
}
to get the linkage correct. If the header file is provided by someone else then it's not good practice to change it (because then you can't update it easily), so it's better to wrap the header file with your own guard (possibly in your own header file).
extern "C" isn't (AFAIK) ANSI C, so can't be included in normal C code without the preprocessor guards.
In response to your edit:
If you are using a C++ compiler, and you declare a function as extern "C" in the header file, you do not need to also declare that function as extern "C" in the implementation file. From section 7.5 of the C++ standard (emphasis mine):
If two declarations of the same
function or object specify different
linkage-specifications (that is, the
linkage-specifications of these
declarations specify different
string-literals), the program is
ill-formed if the declarations appear
in the same translation unit, and the
one definition rule
applies if the declarations appear in
different translation units. Except
for functions with C++ linkage, a
function declaration without a linkage
specification shall not precede the
first linkage specification for that
function. A function can be declared
without a linkage specification after
an explicit linkage specification has
been seen; the linkage explicitly
specified in the earlier declaration
is not affected by such a function
declaration.
I'm not convinced it's good practice though, since there's the potential for the linkage specifications to diverge by accident (if, for example, the header file containing the linkage specification isn't included in the implementing file). I think it's better to be explicit in the implementation file.
They only need to go in anything that is included by other source files.
With some idioms you'll find people including source files.
They should be added to all files, that get included in other files.
Normally, one doesn't include source files.
Apologia
The question has changed to be much clearer what it was asking about. This answer addressed the original question, when it was at least debatable whether it was discussing guards against multiple inclusion in header files - which is what my answer addresses. Clearly, if the question had been as clear then as it is now, I would not have submitted this answer.
Original answer
No, it is not necessary to include the guards in the C code too.
If the header file 'header.h' says:
#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
...
#endif
Then it is perfectly safe for a source file 'source.c' to say:
#include "header.h"
It is also safe for other headers to include 'header.h'.
However, people note that opening a header file and reading it takes time, which slows up a compilation, so sometimes people do things like:
#ifndef HEADER_H_INCLUDED
#include "header.h"
#endif
This means that if some other header included in 'source.c' has already included 'header.h', then the '#include' is not re-processed. (Or, if 'header.h' has already been included directly in 'source.c', though that's a silly buglet.)
So, when encountered, it is likely to be an attempt to optimize the compilation performance. It is far from clear that it buys you much; modern C preprocessors are fairly intelligent about the issue and will avoid re-including the file if they can. And there's always a risk that the test in 'source.c' has a typo (#ifndef HEARER_H_INCLUDED, perhaps) in which case the test slows the compilation because the preprocessor tests the irrelevant condition and then proceeds to include 'header.h' after all. It is 'safe'; the header is itself protected-- or should be.
If you see the code in 'source.c' also doing '#define HEADER_H_INCLUDED', then there are problems. The #define has to be either before or after the #include, and neither is good as a general technique.
If 'source.c' does '#define HEADER_H_INCLUDED' before including 'header.h', then if the guard appears in 'header.h', the contents of the header will not be included. If the guard does not appear in 'header.h', then things work OK.
If 'source.c' does '#define HEADER_H_INCLUDED' after including 'header.h', then if the guard appears in 'header.h', we get a benign redefinition of HEADER_H_INCLUDED. If 'header.h' does not contain the guard but does include a file which includes 'header.h', you are not protected from multiple inclusion after all.
Note that body of the header appears after the '#define HEADER_H_INCLUDED'. This is again protection if nested includes include 'header.h'.
You mean the 'extern c' preprocessors? They have to be on the function definition as well as that affects how the function call is stored in the compiled binary. Its only really needed if you are linking compiled c++ together with c which is compiled as C (as opposed to c in a .cpp file).
The "C" guards have two purposes:
When your code is compiled, the functions will be exported in a way that will allow a non C++ compiler/linker to use them (no C++ name mangling etc.)
When a C++ compiler uses your header files, it will know that it should bind the symbols in the C way which in turn will make sure that the resulting program will link successfully. They don't carry a meaning for a non C++ compiler but since the symbols were generated in C-style in (1) this is the desired effect.
Since you include the header with the "C" guards also in your implementation file, the information on how the symbols should be created at compile time is available to the compiler and the compiler will create the symbols in a way that can be used by a non C++ compiler. Consequently you only need to specify extern "C" in your header file as long as the header file is also included by the implementation file.
it is not required for extern to be used in source files, if they are used in the header file and that file is included by the rest of the source files.
As far as I remember the standard, all function declarations are considered as "extern" by default, so there is no need to specify it explicitly. That doesn't make this keyword useless since it can also be used with variables (and it that case - it's the only solution to solve linkage problems). But with the functions - yes, it's optional.
A little more verbose answer is that it allows you to use variables compiled in another source code file, but doesn't reserve memory for the variable. So, to utilise extern, you have to have a source code file or a library unit that contains memory space for the variable on the top level (not within functions). Now, you can refer to that variable by defining an extern variable of the same name in your other source code files.
In general, the use of extern definition should be avoided. They lead easily to unmanagable code and errors that hard to locate. Of course, there are examples where other solutions would be impractical, but they are rare. For example, stdin and stdout are macros that are mapped to an extern array variable of type FILE* in stdin.h; memory space for this array is in a standard C-library unit.
We had always only added extern "C" to the header definitions, but this allows the C++ code to implement the function with a different signature via overloading without errors and yet it doesn't mangle the symbol definition so at link times it uses this mismatching function.
If the header and the definition both have extern "C" then a mismatched signature generates an error with Visual Studio 2017 and with g++ 5.4.
This following code compiles without an error for Visual Studio 2017 and g++ 5.4
extern "C" {
int test(float a, int b);
}
int test(int b)
{
return b;
}
It seems that gcc mangles the symbol name in this case but Visual Studio 2017 does not.
However including the extern "C" with the definition catches the mismatch at compile time.
extern "C" {
int test(float a, int b);
}
extern "C" int test(int b)
{
return b;
}
gives the following error on g++:
g++ -c -o test.o test.cpp
test.cpp: In function ‘int test(int)’:
test.cpp:4:26: error: conflicting declaration of C function ‘int test(int)’
extern "C" int test(int b)
^
test.cpp:2:9: note: previous declaration ‘int test(float, int)’
int test(float a, int b);
or with cl
cl /c test.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27042 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
test.cpp
test.cpp(4): error C2733: 'test': second C linkage of overloaded function not allowed
test.cpp(2): note: see declaration of 'test'