The first kind of understanding
For example, you have developed a DLL library in C + +, in order to enable the C language to call your DLL output (export) function, you need to use extern "C" to force the compiler not to modify your
The name of the function.
In general, you can often see code similar to the following in the header file of the C language:
#ifdef __cplusplus
extern "C" {
#endif
/**** some declaration or so *****/
#ifdef __cplusplus
}
#endif/* End of __cplusplus * *
So, what is the use of this formulation? In fact, this is a form of syntax that allows CPP to be used with the C interface. The reason for this is that some of the differences between the two languages
The cause of the differences. Because CPP supports polymorphism, that is, functions that have the same function name can perform different functions, the CPP is usually a parameter to distinguish between the specific invocation of which function. In
At compile time, the CPP compiler joins the parameter type with the function name, so that after the program is compiled into the target file, the CPP compiler can directly base the symbol name in the target file
Connect multiple destination files to a target file or executable file. But in C, because there is no notion of polymorphism at all, the C compiler does not add to the function name before it is compiled
With an underscore, nothing is done (at least a lot of compilers do this). For this reason, when using CPP and C mixed programming, there may be problems. False
A function is defined in a header file:
int foo (int a, int b);
The implementation of this function is in a. c file, and the function is called in the. cpp file. Then, when the CPP compiler compiles this function, it is possible to put this function
Name to _fooii, and here the first and second parameters of the function are integral types. The C compiler is likely to compile this function name into _foo. In other words, the CPP compiler has to
To the destination file, the Foo () function is referenced by the _FOOII symbol, and in the target file generated by the C compiler, the Foo () function is referred to by _foo. But when the connector works, it
Regardless of what language the upper level uses, it can only recognize the symbols in the target file. The connector will then find that the Foo () function is called in. cpp, but it is not found in other destination files
To _fooii this symbol, and then prompts for an error in the connection process. extern "C" {} This form of syntax is used to solve this problem. This article will illustrate the problem with an example.
First, let's assume that there are three files:
* FILE:TEST_EXTERN_C.H * *
#ifndef __test_extern_c_h__
#define __test_extern_c_h__
#ifdef __cplusplus
extern "C" {
#endif
/*
* This is a test function, which calculate
* The multiply of A and B.
*/
extern int thisistest (int a, int b);
#ifdef __cplusplus
}
#endif/* End of __cplusplus * *
#endif
Only one function is defined in this header file, Thisistest (). This function is defined as an external function that can be included in other program files. Suppose the thisistest () function
The implementation is located in the test_extern_c.c file:
* TEST_EXTERN_C.C * *
#include "test_extern_c.h"
int thisistest (int a, int b)
{
return (A + B);
}
As you can see, the implementation of the Thisistest () function is very simple, which is to return the result of the addition of two parameters. Now, suppose you want to call the Thisistest () function from the CPP:
* main.cpp * *
#include "test_extern_c.h"
#include <stdio.h>
#include <stdlib.h>
Class FOO {
Public
int bar (int a, int b)
{
printf ("result=%i/n", Thisistest (A, b));
}
};
int main (int argc, char **argv)
{
int a = Atoi (argv[1]);
int b = atoi (argv[2]);
Foo *foo = new Foo ();
Foo->bar (A, b);
return (0);
}
In this CPP source file, a simple class foo is defined, and the Thisistest () function is called in its member function bar (). Look below if you compile test_extern_c.c with GCC
, and what happens when you use g++ to compile main.cpp and connect to TEST_EXTERN_C.O:
[Cyc@cyc src]$ gcc-c TEST_EXTERN_C.C
[Cyc@cyc src]$ g++ main.cpp TEST_EXTERN_C.O
[Cyc@cyc src]$./a.out 4 5
Result=9
As you can see, the program does not have any exceptions and works exactly as expected. So what happens if you comment out the lines of extern "C" {} in test_extern_c.h?
The contents of the test_extern_c.h file after the annotation are as follows:
* TEST_EXTERN_C.H * *
#ifndef __test_extern_c_h__
#define __test_extern_c_h__
#ifdef __cplusplus
extern "C" {
#endif
/*
/* This is a test function, which calculate
* The multiply of A and B.
*/
extern int thisistest (int a, int b);
#ifdef __cplusplus
// }
#endif/* End of __cplusplus * *
#endif
, other files do not make any changes and still compile test_extern_c.c and main.cpp files in the same way:
[Cyc@cyc src]$ gcc-c TEST_EXTERN_C.C
[Cyc@cyc src]$ g++ main.cpp TEST_EXTERN_C.O
/TMP/CCA4ETJJ.O (. gnu.linkonce.t._zn3foo3bareii+0x10): In function ' Foo::bar (int, int) ':
: Undefined reference to ' thisistest (int, int) '
Collect2:ld returned 1 exit status
An error occurred while compiling the main.cpp, and the connector LD hint could not find a reference to the function thisistest ().
To clarify the cause of the problem, we use the following method to compile the target file, and then look at what symbols are in the target file:
[Cyc@cyc src]$ gcc-c TEST_EXTERN_C.C
[Cyc@cyc src]$ objdump-t TEST_EXTERN_C.O
Test_extern_c.o:file format elf32-i386
SYMBOL TABLE:
00000000 L DF *abs* 00000000 TEST_EXTERN_C.C
00000000 L D. Text 00000000
00000000 L D. Data 00000000
00000000 L. BSS 00000000
00000000 L D. Comment 00000000
00000000 G F. Text 0000000b thisistest
[Cyc@cyc src]$ g++-C main.cpp
[Cyc@cyc src]$ objdump-t MAIN.O
Main.o:file format elf32-i386
Mymbol TABLE:
00000000 L DF *abs* 00000000 Main.cpp
00000000 L D. Text 00000000
00000000 L D. Data 00000000
00000000 L. BSS 00000000
00000000 L D. Rodata 00000000
00000000 L D. Gnu.linkonce.t._zn3foo3bareii 00000000
00000000 L D. Eh_frame 00000000
00000000 L D. Comment 00000000
00000000 G F. Text 00000081 Main
00000000 *und* 00000000 Atoi
00000000 *und* 00000000 _ZNWJ
00000000 *und* 00000000 _ZDLPV
00000000 W F. Gnu.linkonce.t._zn3foo3bareii 00000027 _zn3foo3bareii
00000000 *und* 00000000 _z10thisistestii
00000000 *und* 00000000 printf
00000000 *und* 00000000 __gxx_personality_v0
As you can see, after compiling test_extern_c.c with GCC, there is a thisistest symbol in its target file test_extern_c.o, which is defined in the source file.
Thisistest () function. And after the adoption of g++ compiled main.cpp, in its target file main.o has a _z10thisistestii symbol, this is through the g++ compiler "powder
The function name after "broken". The last two characters I indicate that the first and second parameters are integral types. And why add a prefix _z10 I don't know, but it doesn't affect our
Discussion, so do not take care of it. Obviously, that's where the reason is, and the principle is explained at the beginning of this article.
So, why the use of extern "C" {} form will not have this problem, we will look at when the test_extern_c.h using the form of extern "C" {} to compile the target
What symbols are in the file:
[Cyc@cyc src]$ gcc-c TEST_EXTERN_C.C
[Cyc@cyc src]$ objdump-t TEST_EXTERN_C.O
Test_extern_c.o:file format elf32-i386
SYMBOL TABLE:
00000000 L DF *abs* 00000000 TEST_EXTERN_C.C
00000000 L D. Text 00000000
00000000 L D. Data 00000000
00000000 L. BSS 00000000
00000000 L D. Comment 00000000
00000000 G F. Text 0000000b thisistest
[Cyc@cyc src]$ g++-C main.cpp
[Cyc@cyc src]$ objdump-t MAIN.O
Main.o:file format elf32-i386
SYMBOL TABLE:
00000000 L DF *abs* 00000000 Main.cpp
00000000 L D. Text 00000000
00000000 L D. Data 00000000
00000000 L. BSS 00000000
00000000 L D. Rodata 00000000
00000000 L D. Gnu.linkonce.t._zn3foo3bareii 00000000
00000000 L D. Eh_frame 00000000
00000000 L D. Comment 00000000
00000000 G F. Text 00000081 Main
00000000 *und* 00000000 Atoi
00000000 *und* 00000000 _ZNWJ
00000000 *und* 00000000 _ZDLPV
00000000 W F. Gnu.linkonce.t._zn3foo3bareii 00000027 _zn3foo3bareii
00000000 *und* 00000000 Thisistest
00000000 *und* 00000000 printf
00000000 *und* 00000000 __gxx_personality_v0
Notice what's different here and the previous one, as you can see, in the two target files, there is a symbol thisistest, which refers to the thisistest () function. Explicitly
However, the same thisistest symbol is present in the two target files, so that they refer to the actual same function, so that the two target files are connected together, usually
Occurrences of the thisistest symbol in the program code snippet are replaced with the actual address of the thisistest () function. In addition, you can see that only the functions surrounded by extern "C" {}
With such a target symbolic form, for the member function of the Foo class in Main.cpp, the symbolic names after the two compilations are "crushed".
Therefore, combining the above analysis, we can draw the following conclusion: the use of extern "C" {} This form of declaration, can make the interface between CPP and C interoperability, not due to the language
The internal mechanism of speech causes errors when connecting to the target file. It should be stated that the above conclusions are based on the results of my experiment. Because the CPP is not used very much, understand
is very small, so it is not very clear about the internal processing mechanism, please refer to the relevant information if you need to know the details of the problem.
The second kind of understanding
This code is often seen in the CPP code:
#ifdef __cplusplus
extern "C" {
#endif
A piece of code
#ifdef __cplusplus
}
#endif
What exactly does this code mean? First of all, __cplusplus is a custom macro in CPP, so the definition of this macro means that this is the code for a CPP, that is, the above
The meaning of the code is: if this is a section of CPP code, then add extern "C" {and} to process the code.
To understand why extern "C" is used, you have to start with the overload handling of functions in CPP. In C + +, in order to support the overload mechanism, in compiling the generated assembler code, the function
Name to do some processing, such as the return type of functions, and so on. And in C, it's just a simple function name that doesn't add other information. That is to say: C + + and C-pair-generated letters
The processing of a number of names is not the same.
For example, for the following simple function, let's look at the changes in the assembly code that is added and not added to extern "C":
int f (void)
{
return 1;
}
The assembly code generated when adding an extern "C" is:
. File "Test.cxx"
. text
. Align 2
. Globl _f
. def _f;. SCL 2;. type;. endef
_f:
PUSHL%EBP
MOVL%esp,%EBP
MOVL $,%eax
POPL%EBP
Ret
But after the extern "C" is not added
. File "Test.cxx"
. text
. Align 2
. Globl __Z1FV
. def __Z1FV;. SCL 2;. type;. endef
__Z1FV:
PUSHL%EBP
MOVL%esp,%EBP
MOVL $,%eax
POPL%EBP
Ret
The two pieces of assembly code are also produced using the Gcc-s command, all the places are the same, except the resulting function name, one is _f, one is __Z1FV.
Having understood the effect of adding and not joining extern "C" on the name of the function, we continue our discussion of why we need to use extern "C". The father of C + + when designing C + +
, considering that there is already a large number of C code, in order to support the original C code and have written C library, need to support C in C + +, and extern "C" is one of the strategies
。
Imagine a situation where a library file is already written in C and works well, and we need to use this library file at this time, but we need to use C + + to write this new generation
Code. If this code uses C + + to link this C library file, then there will be a link error. Let's take a look at the code: first, we use the C process to write a
function, which means assuming that the function was written in C at the time:
f1.c
extern "C"
{
void F1 ()
{
Return
}
}
The compile command is: gcc-c f1.c-o F1.O produces a library file called F1.O. Write another code to call this F1 function:
Test.cxx
This extern indicates that the F1 function is defined elsewhere so that you can pass
Compile, but the link is still needed
Link to the original library file.
extern void F1 ();
int main ()
{
F1 ();
return 0;
}
by Gcc-c Test.cxx-o TEST.O produces a file called TEST.O. We then used gcc TEST.O f1.o to link two files, but there was an error, the wrong hint
Is:
TEST.O (. Text + 0x1f): Test.cxx:undefine reference to ' F1 () '
That is, when compiling test.cxx, the compiler uses C + + to process the F1 () function, but actually the linked library file is handled in C to handle the function,
There will be an error in the chain: because the linker cannot find the function.
Therefore, in order to call in C + + code in the library file written in, you need to use extern "C" to tell the compiler: This is a C-written library files, please use the C way to link them.
For example, now we have a C library file, its header file is f.h, the resulting lib file is f.lib, then if we want to use this library file in C + +, we need to write
:
extern "C"
{
#include "f.h"
}
To get back to the problem above, if you want to correct the link error, we need to rewrite test.cxx:
extern "C"
{
extern void F1 ();
}
int main ()
{
F1 ();
return 0;
}
Recompile and the link will pass.
Summarize
C and C + + are different ways of handling functions. extern "C" is a means to enable C + + to invoke C writing library files, if you want to prompt the compiler to use C to handle functions, then use extern "C" to explain.