C and C + + mixed programming (use of __cplusplus and external "C")

Source: Internet
Author: User

Transferred from: http://blog.csdn.net/ljfth/article/details/3965871

The first kind of understanding
For example, you have developed a DLL library in C + +, in order for C to be able to call your DLL output (export) function, you need to use extern "C" to force the compiler not to modify your

The function name.

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 is because some of the differences between the two languages

caused by the different. 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. In

When compiling, the CPP compiler joins the parameter types and function names, so that after the program is compiled into the target file, the CPP compiler can directly follow the symbol name in the target file

Connect multiple target files into a single target file or executable file. In C, however, because there is no concept of polymorphism at all, the C compiler, in addition to the function name, is added at compile time.

Add an underscore and do nothing (at least a lot of compilers do). For this reason, there may be problems when using CPP and C mixed programming. False

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 put this function

The name is changed to _fooii, where the II represents the first and second parameters of the function are integral types. The C compiler is likely to compile this function name into _foo. In other words, the CPP compiler has to

To the target file, 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

Regardless of the language used in the upper layer, it only recognized the symbols in the target file. As a result, the connector will find that the Foo () function is called in. cpp, but it is not found in other target files

To _fooii this symbol, and then prompted the connection process error. 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 __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

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 thisistest () function

Implementation is located 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);

}

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>

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 (). Take a look below if you are using GCC to compile TEST_EXTERN_C.C

, and what happens when you 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:

/* 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

, 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 defined in the source file.

Thisistest () function. With g++ compiled main.cpp, in its target file main.o there is a _z10thisistestii symbol, this is the g++ compiler "powder

The function name after the break. The last two characters I represent the first parameter and the second parameter are integral types. And why add a prefix _z10 I don't know, but it doesn't affect our

Discussion, so do not take care of 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 we'll take a look at the compiled target when test_extern_c.h takes the form of extern "C" {}

Which symbols are in the 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 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. Explicitly

However, the same thisistest symbol exists in all two target files at this point, so it is considered that they refer to the same function as the actual one, so that the two target files are connected together, usually

Where there are thisistest symbols in the program code snippet, the actual address of the thisistest () function is substituted. In addition, you can see that only the functions surrounded by extern "C" {}

In this form of target notation, for the member functions of the Foo class in Main.cpp, the symbolic names after two compilations are "crushed".

Therefore, 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 language

The internal mechanism causes errors when connecting to the target file. 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 much, understand

Very little, so it is not very clear what the internal processing mechanism is, so please refer to the relevant information if you need to understand the details of this problem.

The second kind of understanding
This code is often seen in the CPP code:

#ifdef __cplusplus

extern "C" {

#endif

A section of code

#ifdef __cplusplus

}

#endif

What does this kind of code mean? First of all, __cplusplus is a custom macro in CPP, then the definition of this macro means that this is a CPP code, that is, the above

The meaning of the code is: if this is a piece of CPP code, then add the extern "C" {and} to process the code in it.

To understand why the extern "C" is used, you have to start with the overloaded handling of the function from CPP. In C + +, in order to support overloading mechanism, in compiling the generated assembly code, the function

Name to do some processing, such as the return type of the function, and so on. And in C, it's just a simple function name that doesn't include any other information. That is, C + + and C are generated by the letter

The processing of several names is not the same.

For example, for a simple function, let's look at the changes in the assembly code produced by adding and not joining extern "C":

int f (void)

{

return 1;

}

The assembly code generated when the extern "C" is added is:

. File "Test.cxx"

. text

. Align 2

. Globl _f

. def _f;. SCL 2;. type;. endef

_f:

PUSHL%EBP

MOVL%esp,%EBP

MOVL $,%eax

POPL%EBP

Ret

But after not adding the extern "C"

. File "Test.cxx"

. text

. Align 2

. Globl __Z1FV

. def __Z1FV;. SCL 2;. type;. endef

__Z1FV:

PUSHL%EBP

MOVL%esp,%EBP

MOVL $,%eax

POPL%EBP

Ret

The two-piece assembly code is also produced using the Gcc-s command, where all the same, except for the resulting function name, one is _f, and the other is __Z1FV.

Understand the effect of adding and not adding extern "C" to the function name, we continue our discussion: Why do I need to use extern "C"? The parent of C + + at the time of designing C + +

, in view of the existence of a large number of C code, in order to support the original C code and have already written C library, need in C + + as much as possible to support C, and extern "C" is one of the strategies

Think of the situation: a library file has been written in C and run very well, this time we need to use this library file, but we need to use C + + to write this new generation

Code. If the code uses C + + to link the C library file, then there will be a link error. Let's take a look at the code: first, we use C's processing to write a

function, that is to say that the function was written in C:

f1.c

extern "C"

{

void F1 ()

{

Return

}

}

The compile command is: Gcc-c f1.c-o f1.o produced a library file called F1.O. Write another piece of code to call this F1 function:

Test.cxx

This extern means that the F1 function is defined elsewhere, which can be

Compile, but the link still needs to be

Link to the original library file.

extern void F1 ();

int main ()

{

F1 ();

return 0;

}

A file called TEST.O is produced by Gcc-c Test.cxx-o TEST.O. Then we used gcc TEST.O f1.o to link two files, but there was an error, the wrong hint

Is:

TEST.O (. Text + 0x1f): Test.cxx:undefine reference to ' F1 () '

In other words, when compiling test.cxx, the compiler uses C + + to handle the F1 () function, but actually the linked library file is in the form of C to handle the function,

The link will not go wrong: Because the linker cannot find the function.

Therefore, in order to call in C + + code in the library file, you need to use the extern "C" to tell the compiler: This is a C-written library file, please link them in C way.

For example, now we have a C library file, its header file is f.h, the resulting lib file is f.lib, then if we want to use this library file in C + +, we need to write

:

extern "C"

{

#include "f.h"

}

Back to the question above, if you want to correct the link error, we need to rewrite test.cxx:

extern "C"

{

extern void F1 ();

}

int main ()

{

F1 ();

return 0;

}

Recompile and the link will be gone.

Summarize

C and C + + treat functions differently. extern "C" is a means to enable C + + to invoke C-writing library files, and if you want to use C as the compiler prompts to handle functions, then use extern "C" to illustrate.

C and C + + mixed programming (use of __cplusplus and external "C")

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.