C and C + + mixed compilation

Source: Internet
Author: User

about Extern_c

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

[Plain]View Plaincopyprint?
    1. #ifdef __cplusplus
    2. extern "C" {
    3. #endif
    4. /**** some declaration or so *****/
    5. #ifdef __cplusplus
    6. }
    7. #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:

[Plain]View Plaincopyprint?
    1. 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:

[Plain]View Plaincopyprint?
  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/* End of __cplusplus */
  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:

[Plain]View Plaincopyprint?
    1. /* TEST_EXTERN_C.C */
    2. #include "test_extern_c.h"
    3. int thisistest (int a, int b)
    4. {
    5. return (A + B);
    6. }

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:

[Plain]View Plaincopyprint?
  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. }

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:

[Plain]View Plaincopyprint?
    1. [Email protected] src]$ gcc-c TEST_EXTERN_C.C
    2. [Email protected] src]$ g++ main.cpp TEST_EXTERN_C.O
    3. [Email protected] src]$./a.out 4 5
    4. 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: [Plain]View Plaincopyprint?
  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/* End of __cplusplus */
  15. #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:

[Plain]View Plaincopyprint?
    1. [Email protected] src]$ gcc-c TEST_EXTERN_C.C
    2. [Email protected] src]$ g++ main.cpp TEST_EXTERN_C.O
    3. /TMP/CCA4ETJJ.O (. gnu.linkonce.t._zn3foo3bareii+0x10): In function ' Foo::bar (int, int) ':
    4. : Undefined reference to ' thisistest (int, int) '
    5. 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:

[Plain]View Plaincopyprint?
  1. [Email protected] src]$ gcc-c TEST_EXTERN_C.C
  2. [Email protected] src]$ objdump-t TEST_EXTERN_C.O
  3. Test_extern_c.o:file format elf32-i386
  4. SYMBOL TABLE:
  5. 00000000 L DF *abs* 00000000 TEST_EXTERN_C.C
  6. 00000000 L D. Text 00000000
  7. 00000000 L D. Data 00000000
  8. 00000000 L D. BSS 00000000
  9. 00000000 L D. Comment 00000000
  10. 00000000 G F. Text 0000000b thisistest
  11. [Email protected] src]$ g++-C main.cpp
  12. [Email protected] src]$ objdump-t MAIN.O
  13. Main.o:file format elf32-i386
  14. SYMBOL TABLE:
  15. 00000000 L DF *abs* 00000000 Main.cpp
  16. 00000000 L D. Text 00000000
  17. 00000000 L D. Data 00000000
  18. 00000000 L D. BSS 00000000
  19. 00000000 L D. Rodata 00000000
  20. 00000000 L D. Gnu.linkonce.t._zn3foo3bareii 00000000
  21. 00000000 L D. Eh_frame 00000000
  22. 00000000 L D. Comment 00000000
  23. 00000000 G F. Text 00000081 Main
  24. 00000000 *und* 00000000 Atoi
  25. 00000000 *und* 00000000 _ZNWJ
  26. 00000000 *und* 00000000 _ZDLPV
  27. 00000000 W F. Gnu.linkonce.t._zn3foo3bareii 00000027 _zn3foo3bareii
  28. 00000000 *und* 00000000 _z10thisistestii
  29. 00000000 *und* 00000000 printf
  30. 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.

[Plain]View Plaincopyprint?
  1. [Email protected] src]$ gcc-c TEST_EXTERN_C.C
  2. [Email protected] src]$ objdump-t TEST_EXTERN_C.O
  3. Test_extern_c.o:file format elf32-i386
  4. SYMBOL TABLE:
  5. 00000000 L DF *abs* 00000000 TEST_EXTERN_C.C
  6. 00000000 L D. Text 00000000
  7. 00000000 L D. Data 00000000
  8. 00000000 L D. BSS 00000000
  9. 00000000 L D. Comment 00000000
  10. 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" {}:

[Plain]View Plaincopyprint?
  1. [Email protected] src]$ g++-C main.cpp
  2. [Email protected] src]$ objdump-t MAIN.O
  3. Main.o:file format elf32-i386
  4. SYMBOL TABLE:
  5. 00000000 L DF *abs* 00000000 Main.cpp
  6. 00000000 L D. Text 00000000
  7. 00000000 L D. Data 00000000
  8. 00000000 L D. BSS 00000000
  9. 00000000 L D. Rodata 00000000
  10. 00000000 L D. Gnu.linkonce.t._zn3foo3bareii 00000000
  11. 00000000 L D. Eh_frame 00000000
  12. 00000000 L D. Comment 00000000
  13. 00000000 G F. Text 00000081 Main
  14. 00000000 *und* 00000000 Atoi
  15. 00000000 *und* 00000000 _ZNWJ
  16. 00000000 *und* 00000000 _ZDLPV
  17. 00000000 W F. Gnu.linkonce.t._zn3foo3bareii 00000027 _zn3foo3bareii
  18. 00000000 *und* 00000000 Thisistest
  19. 00000000 *und* 00000000 printf
  20. 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

enclose the functions of the entire C file.

C and C + + mixed compilation

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.