Article From:https://www.cnblogs.com/oneway1990/p/9124674.html

About extern_C
Usually, in the header files of the C language, you can often see code like this.

#ifdef  __cplusplus  
extern "C" {  
#endif  


/**** some declaration or so *****/  


#ifdef  __cplusplus  
}  
#endif  /* end of __cplusplus */  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

So, what’s the use of this way of writing? In fact, this is a grammatical form to allow CPP to interface with C. The reason for this is due to some differences between the two languages. Because CPP supports polymorphism, that is, functions with the same function name can be completed differently.The function of CPP is to distinguish which function is invoked by parameters. When compiling, the CPP compiler connects the parameter type and the function name together, and after the program is compiled into a target file, the CPP compiler can direct multiple target texts directly according to the symbol name in the target file.The component is connected to a target file or executable file. But in the C language, because there is no concept of polymorphism, the C compiler will not do anything in addition to adding a underline before the function name (at least a lot of compilers do it). For this reason, when using CWhen PP and C are mixed programming, there may be problems. Suppose that a function is defined in a header file:

int foo(int a, int b);  
  • 1

The implementation of this function is located 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 II indicates that the first and second parameters of the function are integral.. 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, and in the target file generated by the C compiler, the foo () function is represented by _foo. butWhen the connector works, it can ignore whatever language the upper layer uses, and it only recognizes the symbols in the target file. The connector will then find that the foo () function is called in the.Cpp, but the _fooii symbol cannot be found in the other target files, and the connection is prompted to make a mistake.Extern “C” {} this grammatical form is used to solve this problem. This article will illustrate this problem with an example.

The first assumption is that there are three such documents 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  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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 implementation of the ThisIsTest () function is 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);  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

As you can see, the implementation of the ThisIsTest () function is very simple, that is, to return the result of the addition of the two parameters. Now, suppose we call the ThisIsTest () function from 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);  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

In this CPP source file, a simple class FOO is defined, and the ThisIsTest () function is called in its member function bar (). Let’s take a look at how to compile test_extern_c.c with GCC and compile main.cpp with g++.What will happen if you connect with 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

You can see that the program has no exceptions and works exactly as expected. So what happens if the lines of extern “C” {} in test_extern_c.h are annotated? The content of the test_extern_c.h file after the annotation is likeBelow:

 /* 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  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

In addition, other documents do not make any changes, and the same way is used to compile test_extern_c.c and main.cpp files:

[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  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

When you compile main.cpp, you will make a mistake. Connector LD hints that no reference to function ThisIsTest () can be found.

In order to explain the cause of the problem more clearly, we use the following way to compile the target file first and see what symbols in the target file are in the end.

[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  

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    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  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

As you can see, after the test_extern_c.c is 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. andAfter using g++ to compile main.cpp, there is a _Z10ThisIsTestii symbol in its target file main.o, which is the function name after the g++ compiler “pulverization”. The last two characters I represent the first and second parameters.It’s an integer. It is not clear why I want to add a prefix _Z10, but this does not affect our discussion, so we will not control it. Obviously, this is the reason, and its principle has been explained at the beginning of this paper.


[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  

00000000 g     F .text  0000000b ThisIsTest  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

So, why not have this problem in the form of extern “C” {}, and let’s look at the symbols in the target file that is compiled when test_extern_c.h uses the form of extern “C” {}.

[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  

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  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

Notice that there is no difference between the front and the front, and you can see that in the two target file, there is a symbol ThisIsTest, which refers to the ThisIsTest () function. Obviously, the same ThisIsTes is present in the two target files at this time.T symbols, so they think they refer to the same function, and then connect two target files together, where the ThisIsTest symbol in the program code segment is replaced by the actual address of the ThisIsTest () function. In addition, it can be seen, only byThe functions that are surrounded by extern “C” {} adopt such a form of target symbols, and for the member functions of the FOO class in main.cpp, the symbol names of the two compiling methods are “crushed”.

Therefore, as a result of the above analysis, we can draw the following conclusion: the use of extern “C” {} in this form of declaration can make the interface between CPP and C interworking, and will not cause errors when the target file is connected to the internal mechanism of the language. It needs to be explained,The above conclusion is only based on my test results. Because CPP is not used much and knows very little, the internal processing mechanism is not very clear. If you need to know the details of this problem, please refer to the relevant information.

Remarks:
1. For the function func () written in C file to be used in CPP, you only need to add the extern “C” statement in the header file of the C file. For example, extern “C” func () {… }

Of course, it can be used

#ifdef __cplusplus

extern "C" {

#endif

and#ifdef __cplusplus

}

#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

All the functions of the entire C file are included.


Second: an analysis of the use of extern “C”

Introduction

C++It preserves some of the characteristics of procedural languages, so it can define global variables and functions that do not belong to any class. But, after all, C++ is an object oriented programming language. In order to support the heavy load of the function, the way C++ handles the global function is obviously different from that of the C.
extern “C”The main function is to enable C++ code to correctly invoke other C language codes. Adding the extern “C” will instruct the compiler part of the code to be compiled in C instead of C++. Because C++ supports function overloading, the compiler will compile the function in the process.The parameter type of the function is also added to the compiled code, not just the function name; and the C language does not support the function overloading, so the functions that compile the C language code do not bring on the parameter type of the function, generally including the function name.
For example, you have developed a DLL library with C, and in order to enable C + + to call your DLL output (Export) function, you need to use extern “C” to force the compiler not to modify your function name.

Expose extern “C”

Talk about the standard headers

#ifndef __INCvxWorksh  /*Prevent the header file from being repeated referenced * /#define __INCvxWorksh

#ifdef __cplusplus    //__cplusplusIs a custom macro in CPPExtern"C" {          //Tell the compiler that this part of the code is compiled in C format instead of C++.#endif

    /**** some declaration or so *****/  

#ifdef __cplusplus
}
#endif

#endif /* __INCvxWorksh */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

extern “C”Meaning

extern “C” Double meanings can be obtained literally: first, the target it is decorated is “extern”; secondly, the target it is decorated is “C”.
The function or variable defined by extern “C” is extern type.
1、externKeyword
externIt is the keyword in the C/C++ language that shows the function and the scope of the global variable (visibility), which tells the compiler that its declared functions and variables can be used in this module or in other modules.
In general, the functions and global variables referenced by this module to other modules in the header file of the module are declared in keyword extern. For example, if module B wants to refer to the global variables and functions defined in the module A, you only need to include the header file of module A. In this way, the module B calls the module AIn the compilation phase, the module B can not find the function at the compile stage, but it will not be wrong; it will find this function from the target code generated by the module A in the link phase.
The key word corresponding to extern is static, and the global variables and functions decorated by it can only be used in this module. Therefore, when a function or variable can only be used by this module, it can not be modified by extern “C”.

2、Variables and functions modified by extern “C” are compiled and linked in C language.
First, let’s look at how a function similar to C is compiled in C++.
As an object-oriented language, C++ supports function overloading while procedural language C does not support it. After the function is compiled by C++, the name in the symbol library is different from that in the C language. For example, suppose the prototype of a function is:
void foo( int x, int y );
The function is compiled by the C compiler and the name is _foo in the symbol library, and the C++ compiler produces names like _foo_int_int (different compilers may produce different names, but all use the same mechanism, and the new name is called “mangled”.Name “).
_foo_int_intSuch a name contains function name, function parameter quantity and type information. C++ relies on this mechanism to realize function overloading. For example, in C++, function void foo (int x, int y) and void foo (int x, int)At y) the symbols generated by compiling are different, and the latter is _foo_int_float.
Similarly, variables in C++ not only support local variables, but also support class member variables and global variables. The class member variables that the user writes may have the same name as the global variables. We distinguish them by “.” In essence, compilers are similar to functions in compilation, and are also taken for variables in classes.A unique name, which is different from the name of the global variable with the same name in the user program.

3、Illustrating
(1)Connection mode when the extern “C” declaration is not added
Suppose that in C++, the header file of the module A is as follows:

// Module A header file moduleA.h#ifndef MODULE_A_H
#define MODULE_A_H
int foo( int x, int y );
#endif
//The function is referenced in module B:// Module B implementation file moduleB.cpp#include "moduleA.h"
foo(2,3);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

In fact, at the connection stage, the linker searches for the symbol _foo_int_int in the target file moduleA.obj generated by module A.

(2)Compiling and linking after the extern “C” Declaration
After adding the extern “C” statement, the header file of module A becomes:


// Module A header file moduleA.h#ifndef MODULE_A_H
#define MODULE_A_H
extern "C" int foo( int x, int y );
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Foo (2,3) is still invoked in the implementation file of module B, and the result is:

<1>AWhen compiling the target code of foo, it did not deal with its name in special way, and adopted C language.

<2>When the linker searches for foo (2,3) for the target code of module B, it looks for the unmodified symbol name _foo.

If the function in module A declares the foo as the extern “C” type, and the module B contains extern int foo (int x, int y), then the module cannot find the function in the module, and vice versa.

extern “C”The real purpose of this statement is to achieve mixed programming between C++ and C and other languages.

Application

C++The code calls the C language code and is used in the header file of C++.
The functions and variables in the C language are quoted in C++. In the C language header file (assuming cExample.h), the following processes are required:

extern "C"
{
#include "cExample.h"
}
  • 1
  • 2
  • 3
  • 4

In the header file of the C language, the external function can only be specified as the extern type, and the extern “C” declaration is not supported in the C language, and the compiler syntax error will appear when the extern “C” is included in the.C file.

/* cLanguage header file: cExample.h * /#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
extern int add(int x,int y);     //Note: it is written as extern "C" int add (int, int).#endif

/* cLanguage implementation file: cExample.c * /#include "cExample.h"
int add( int x, int y )
{
 return x + y;
}

// c++Implement the file, call add:cppFile.cppExtern"C"
{
 #include "cExample.h"        //Note: it is not appropriate here. If it is not compiled, replace it with extern "C" int add (int, int); it can pass.}int main(int argc, char* argv[])
{
 add(2,3);
 return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

If C++ calls a.DLL written in C language, the extern “C” {} should be added when the header file of.DLL is included or the interface function is declared.

When the functions and variables in the C++ language are referenced in C, the header file of C++ needs to add extern “C”, but the header file that declares the extern “C” is not directly referenced in the C language, and the extern “C” function in C++ should be defined only in the C file.Declarations are extern types


//C++Header file cppExample.h#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add( int x, int y );
#endif

//C++Implement file cppExample.cpp#include "cppExample.h"
int add( int x, int y )
{
 return x + y;
}

/* CImplement file cFile.c/ * this will compile error: #include "cExample.h" * /extern int add( int x, int y );
int main( int argc, char* argv[] )
{
 add( 2, 3 );
 return 0;
}
Link of this Article: C/C++ hybrid programming

Leave a Reply

Your email address will not be published. Required fields are marked *