For example, if you have developed a dll library using 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 function name. Generally, you can see code similar to the following in the header file of C language:
# Ifdef _ cplusplus
Extern "C "{
# Endif
/***** Some declaration or so *****/
# Ifdef _ cplusplus
}
# Endif/* end of _ cplusplus */
So what is the purpose of this writing? In fact, this is a syntax form used to enable CPP to interact with C interfaces. This method is used because of some differences between the two languages. Since CPP supports polymorphism, that is, functions with the same function name can complete different functions, CPP usually uses parameters to differentiate which function is called. During compilation, the CPP compiler connects the parameter type and function name. After the program is compiled into the target file, the CPP compiler can directly connect multiple target files to a target file or executable file based on the symbols in the target file. However, in C language, because there is no concept of polymorphism at all, the C compiler will not only add an underline before the function name during compilation, nothing will be done (at least many compilers do this ). For this reason, when using CPP and C Mixed Programming, problems may occur. Assume that a function is defined in a header file:
Int Foo (int A, int B );
The implementation of this function is located in a. c file. At the same time, this function is called in the. cpp file. When the CPP compiler compiles this function, it is possible to change the function name to _ fooii. Here, II indicates that the first and second parameters of the function are integer. The C compiler may compile the function name into _ Foo. That is to say, in the target file obtained by the CPP compiler, the Foo () function is referenced by the _ fooii symbol. In the target file generated by the C compiler, Foo () the function is referred to by _ Foo. However, when the connector works, it can recognize only the symbols in the target file regardless of the language used in the upper layer. Therefore, the connector will find that the Foo () function is called in. cpp, but the _ fooii symbol cannot be found in other target files, so an error occurs during the connection. Extern "C" {} is used to solve this problem. This document describes the problem as an example.
Assume that there are three files as follows:
/* 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
This header file defines only one function, thisistest (). This function is defined as an external function and 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 */
# I nclude "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, that is, the result of adding the two parameters is returned. Now, assume that you want to call the thisistest () function from CPP:
/* Main. cpp */
# I nclude "test_extern_c.h"
# I nclude <stdio. h>
# I nclude <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. Next, let's take a look at what will happen if we use GCC to compile test_extern_c.c and 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 if I comment out the lines of extern "C" {} In test_extern_c.h? The content of the annotated file test_extern_c.h is 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
In addition, other files are not changed, and the test_extern_c.c and Main. cpp files are compiled 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 occurs when compiling main. cpp. The connector LD prompts that reference to the thisistest () function cannot be found.
To better illustrate the cause of the problem, we first compile the target file in the following method, and then see 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 d. BSS 00000000
00000000 l d. Comment 00000000
00000000g 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 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
00000000g 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
We can see that after test_extern_c.c is compiled using gcc, there is a thisistest symbol in the target file test_extern_c.o. This symbol is the thisistest () function defined in the source file. The main is compiled using G ++. after CPP, the main. there is a _ z10thisistestii symbol in O, which is the function name after being "crushed" by the G ++ compiler. The last two characters I indicate that the first and second parameters are both integer. I don't know why I want to add a prefix _ Z10, but it does not affect our discussion, so I don't care about it. Obviously, this is the reason, and its principles have been described at the beginning of this article.
So why can't this problem be solved if the extern "C" {} format is used, let's take a look at the symbols in the target file compiled when test_extern_c.h adopts the extern "C" {} format:
[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 d. BSS 00000000
00000000 l d. Comment 00000000
00000000g 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 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
00000000g 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
Note that there is nothing different from the previous one. We can see that there is a thisistest symbol in both target files. This symbol references the thisistest () function. Obviously, the same thisistest symbol exists in both target files. Therefore, if they reference the same function, the two target files are connected together, the actual address of the thisistest () function is used in all the thisistest symbols in the code segment. In addition, we can also see that the function only surrounded by extern "C" {} adopts the target symbol form, for Main. the member functions of the foo class in CPP, after the two compilation methods, all the symbol names are "broken.
Therefore, based on the above analysis, we can draw the following conclusion: using the declaration in the form of extern "C" {}, the interfaces between CPP and C can be interconnected, there will be no errors when connecting to the target file due to the internal mechanism of the language. It should be noted that the above is just a conclusion based on my test results. Since CPP is not used much and has little knowledge about it, it is not very clear about its internal processing mechanism. If you need to learn more about this problem, please refer to relevant materials.