About Extern_c
Typically, a code similar to the following is often seen 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's the use of this notation? In fact, this is a form of syntax used to enable CPP to interface with C. This approach is due to some differences between the two languages. Because CPP supports polymorphism, that is, functions with the same function name can accomplish different functions, CPP is usually a parameter to distinguish which function is called specifically. At compile time, the CPP compiler joins the parameter types and function names, so after the program is compiled into a target file, the CPP compiler can directly connect multiple target files to a target file or executable file based on the symbol in the target file. In C, however, because there is no concept of polymorphism at all, the C compiler does nothing (at least many compilers do so) at compile time except to add an underscore before the function name. For this reason, there may be problems when using CPP and C mixed programming. Suppose that a function is defined in a header file:
int foo (intint
The implementation of this function is in a. c file, and this function is called in the. cpp file. Then, when the CPP compiler compiles this function, it is possible to change the function name to _fooii, where the II is the first and second parameters of the function are integer. The C compiler is likely to compile this function name into _foo. That is, in the target file that the CPP compiler obtains, the Foo () function is referenced by the _FOOII symbol, whereas in the target file generated by the C compiler, the Foo () function is referred to by _foo. But when the connector works, it does not matter what language is used in the upper layer, it only recognize the symbols in the target file. As a result, the connector will find that the Foo () function is called in the. cpp, but the _FOOII symbol is not found in the other target files, so the connection process is faulted. The syntactic form of extern "C" {} is used to solve this problem. This article shows an example of this issue.
Let's first assume that there are three of these files:
/* file:test_extern_c.h */
#ifndef __test_extern_c_h__#define__test_extern_c_h__#ifdef __cplusplusextern "C" { #endif /** This is a test function, which calculate * the multiply of A and B. */ extern intThisistest (intAintb); #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. Assume that the implementation of the Thisistest () function is in the TEST_EXTERN_C.C file:
/* TEST_EXTERN_C.C */
" test_extern_c.h " int Thisistest (intint b) { return (A + b);
As you can see, the implementation of the Thisistest () function is very simple, which is to return the result of adding 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>classFOO { Public: intBarintAintb) {printf ("result=%i\n", Thisistest (A, b)); } }; intMainintargcChar**argv) { intA = Atoi (argv[1]); intb = Atoi (argv[2]); FOO*foo =NewFOO (); 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 (). Here's a look at what happens if you compile test_extern_c.c with GCC and use g++ to compile main.cpp and connect to TEST_EXTERN_C.O:
[Email protected] src]$ gcc-c TEST_EXTERN_C.C
[Email protected] src]$ g++ main.cpp TEST_EXTERN_C.O
[Email protected] src]$./a.out 4 5
Result=9
As you can see, the program does not have any exceptions and works exactly the way you expect. So what happens if you comment out the lines that are in the test_extern_c.h of extern "C" {}? The contents of the test_extern_c.h file after the comment are as follows:
#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 intThisistest (intAintb); //#ifdef __cplusplus// } //#endif/* End of __cplusplus * / #endif
In addition, other files do not make any changes and still compile the test_extern_c.c and main.cpp files in the same way:
[Email protected] src]$ gcc-c TEST_EXTERN_C.C
[Email protected] 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
Error while compiling main.cpp, the connector LD hint could not find a reference to function Thisistest ().
To better illustrate the cause of the problem, we use the following method to compile the target file and then see what symbols are in the target file.
[Email protected] src]$ gcc-c TEST_EXTERN_C.C
[Email protected] 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 D. BSS 00000000
00000000 L D. Comment 00000000
00000000 G F. Text 0000000b thisistest
[Email protected] src]$ g++-C main.cpp
[Email protected] 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 D. 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 TEST_EXTERN_C.C has been compiled with GCC, there is a thisistest symbol in its target file test_extern_c.o, which is the thisistest () function defined in the source file. After compiling the main.cpp with g++, there is a _z10thisistestii symbol in the target file main.o, which is the function name after the g++ compiler "Smash". The last two characters I represent the first parameter and the second parameter are integral types. And why add a prefix _z10 I'm not sure, but it doesn't affect our discussion, so don't worry about it. Obviously, this is where the reason is, and its principle is explained at the beginning of this article.
[Email protected] src]$ gcc-c TEST_EXTERN_C.C
[Email protected] 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 D. BSS 00000000
00000000 L D. Comment 00000000
00000000 G F. Text 0000000b thisistest
So why does the extern "C" {} form not have this problem, and let's take a look at what symbols in the target file are compiled when test_extern_c.h takes the form of extern "C" {}:
[[email protected] src]$ g++-C main.cpp
[[email protected] 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 br>00000000 l D. Data 00000000
00000000 L d. BSS 00000000
00000000 L D. Rodata 00000000
00000000 L D. gnu.link Once.t._zn3foo3bareii 00000000
00000000 L D. Eh_frame 00000000
00000000 L D. Comment 00000000
00000000 G F. Te XT 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 before, you can see, in two target files, there is a symbol thisistest, this symbol refers to the thisistest () function. Obviously, at this point in the two target files have the same thisistest symbol, so that they refer to the actual function of the same, so the two target files are concatenated together, where there is a program code snippet has thisistest symbol in the place are used Thisistest () Replace the actual address of the function. In addition, it can be seen that only the function surrounded by extern "C" {} takes the form of a target symbol, and for the member functions of the Foo class in Main.cpp, the symbolic names after the two compilations are "crushed".
Therefore, based on the above analysis, we can draw the following conclusion: the use of the extern "C" {} This form of declaration, can make the interface between CPP and C interoperability, not due to the internal mechanism of the language caused by the connection of the target file error. It should be explained that the above is just the conclusion based on the results of my experiment. Since the use of CPP is not very much, the knowledge is very small, so the internal processing mechanism is not very clear, if you need to understand the details of this issue, please refer to the relevant information.
Note:
1. For function func () that is written in the C file to be used in CPP, simply add the extern "C" declaration to the header file of the C file. For example: extern "C" func () {...}
Of course, you can use
#ifdef __cplusplus
extern "C" {
#endif
And
#ifdef __cplusplus
}
#endif
enclosing all the functions of the C file.
C and C + + mixed compilation