extern "C" in C + +

Source: Internet
Author: User

For example, you have developed a DLL library with 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.

Typically, a code similar to the following is often seen in the header file of the C language:

C code
    1. #ifdef __cplusplus
    2. extern "C" {
    3. #endif
    4. /**** some declaration or so *****/
    5. #ifdef __cplusplus
    6. }
    7. #endif
#ifdef __cplusplusextern "C" {#endif/**** some declaration or so *****/#ifdef __cplusplus} #endif

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 (int a, int b);

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:

C code
  1. /* file:test_extern_c.h */
  2. #ifndef __test_extern_c_h__
  3. #define __test_extern_c_h__
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7. /*
  8. * This is a test function, which calculate
  9. * The multiply of A and B.
  10. */
  11. extern int thisistest (int A, int b);
  12. #ifdef __cplusplus
  13. }
  14. #endif
  15. #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:

C code
    1. /* TEST_EXTERN_C.C */
    2. # include "test_extern_c.h"
    3. int thisistest (int A, int b)
    4. {
    5. return (a + B);
    6. }
/* TEST_EXTERN_C.C */#include "test_extern_c.h" int thisistest (int a, int 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:

CPP Code
  1. /* Main.cpp */
  2. # include "test_extern_c.h"
  3. # include <stdio.h>
  4. # include <stdlib.h>
  5. Class FOO {
  6. Public
  7. int bar (int A, int b)
  8. {
  9. printf ("result=%i\n", Thisistest (A, b));
  10. }
  11. };
  12. int main (int argc, char **argv)
  13. {
  14. int a = Atoi (argv[1]);
  15. int b = atoi (argv[2]);
  16. Foo *foo = new Foo ();
  17. Foo->bar (A, b);
  18. return (0);
  19. }
/* 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);  

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:

C code
  1. /* test_extern_c.h */
  2. #ifndef __test_extern_c_h__
  3. #define __test_extern_c_h__
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7. /*
  8. /* This is a test function, which calculate
  9. * The multiply of A and B.
  10. */
  11. extern int thisistest (int A, int b);
  12. #ifdef __cplusplus
  13. // }
  14. #endif
  15. #endif
/* 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   

, other files do not make any changes, and the TEST_EXTERN_C.C and main.cpp files are still compiled 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 is 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

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

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.

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]$ 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 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.

Attention:

When compiling the CPP program with g++, the compiler defines the macro __cplusplus, which determines whether the extern "C" is required depending on whether the __cplusplus is defined.

Summarize:

All of the above are theories, and some programs, then the actual use of the following concentration:

1. Now to write a C-language module for later use (the future project may be C or C + +), the source files are compiled beforehand, compiled into. So or. o are irrelevant. When declaring a function in a header file, it is included with conditional compilation as follows:

C code
    1. #ifdef __cpluscplus
    2. extern "C" {
    3. #endif
    4. Some code
    5. #ifdef __cplusplus
    6. }
    7. #endif
#ifdef __cpluscplusextern "C" {#endif//some code#ifdef __cplusplus} #endif

That is, all function declarations are placed in the some code location.

2. If the module already exists, it may be written by the predecessor of the company, anyway, there is already, the module of the. h file does not have the extern "C" keyword, this module does not want to be changed in the case, you can, in your C + + file, including the module's header file with extern "C ", as follows:

CPP Code
    1. extern "C" {
    2. #include "test_extern_c.h"
    3. }
extern "C" {#include "test_extern_c.h"}

3. In the example above, if you only use the 1 functions in the module and do not need to include the entire module, you can declare the function separately, as in this case, without the Include header file:

CPP Code
    1. extern "C" {
    2. int thisistest (int, int);
    3. }
extern "C" {int thisistest (int, int);}

You can then use this thisistest function in the module.

extern "C" in C + +

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.