📄 mi34.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="EN">
<HEAD>
<TITLE>More Effective C++ | Item 34: Understand how to combine C++ and C in the same program</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 0; setCurrentMax(0);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">
var dingbase = "MI34_DIR.HTM";
var dingtext = "Item M34, P";
if (self == top) {
top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="M34: Combining C and C++ in the same program" -->
<A NAME="33950"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MI33_FR.HTM" TARGET="_top">Item 33: Make non-leaf classes abstract</A> <BR> Continue to <A HREF="./MI35_FR.HTM" TARGET="_top">Item 35: Familiarize yourself with the language standard</A></FONT></DIV>
<P><A NAME="dingp1"></A><font ID="mititle">Item 34: Understand how to combine C++ and C in the same program.</font><SCRIPT>create_link(1);</SCRIPT>
</P>
<A NAME="72194"></A><A NAME="76665"></A>
<P><A NAME="dingp2"></A>
In many ways, the things you have to worry about when making a program out of some components in C++ and some in C are the same as those you have to worry about when cobbling together a C program out of object files produced by more than one C compiler. There is no way to combine such files unless the different compilers agree on implementation-dependent features like the size of <CODE>int</CODE>s and <CODE>double</CODE>s, the mechanism by which parameters are passed from caller to callee, and whether the caller or the callee orchestrates the passing. These pragmatic aspects of mixed-compiler software development are quite properly ignored by <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=cstandard" onMouseOver="self.status='C++ Language Standard Home Page'; return true" onMouseOut="self.status = self.defaultStatus" target="_top">language</NOBR> standardization efforts</A>, so the only reliable way to know that object files from compiler A and compiler B can be safely combined in a program is to obtain assurances from the vendors of A and B that their products produce compatible output. This is as true for programs made up of C++ and C as it is for all-C++ or all-C programs, so before you try to mix C++ and C in the same program, make sure your C++ and C compilers generate compatible object <NOBR>files.<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P><A NAME="36594"></A>
<A NAME="p271"></A>
<P><A NAME="dingp3"></A>
Having done that, there are four other things you need to consider: name mangling, initialization of statics, dynamic memory allocation, and data structure <NOBR>compatibility.<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp4"></A><font ID="mhtitle">Name Mangling</font><SCRIPT>create_link(4);</SCRIPT>
</P>
<A NAME="36595"></A>
<P><A NAME="dingp5"></A>
Name mangling, as you may know, is the process through which your C++ compilers give each function in your program a unique name. In C, this process is unnecessary, because you can't overload function names, but nearly all C++ programs have at least a few functions with the same name. (Consider, for example, the iostream library, which declares several versions of <CODE>operator<<</CODE> and <CODE>operator>></CODE>.) Overloading is incompatible with most linkers, because linkers generally take a dim view of multiple functions with the same name. Name mangling is a concession to the realities of linkers; in particular, to the fact that linkers usually insist on all function names being <NOBR>unique.<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P><A NAME="36644"></A>
<P><A NAME="dingp6"></A>
As long as you stay within the confines of C++, name mangling is not likely to concern you. If you have a function name <CODE>drawLine</CODE> that a compiler mangles into <CODE>xyzzy</CODE>, you'll always use the name <CODE>drawLine</CODE>, and you'll have little reason to care that the underlying object files happen to refer to <CODE>xyzzy</CODE>.<SCRIPT>create_link(6);</SCRIPT>
</P><A NAME="36681"></A>
<P><A NAME="dingp7"></A>
It's a different story if <CODE>drawLine</CODE> is in a C library. In that case, your C++ source file probably includes a header file that contains a declaration like <NOBR>this,<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P>
<A NAME="36687"></A>
<UL><PRE>void drawLine(int x1, int y1, int x2, int y2);
</PRE>
</UL><A NAME="36688"></A>
<A NAME="dingp8"></A><P><A NAME="dingp8"></A>and your code contains calls to <CODE>drawLine</CODE> in the usual fashion. Each such call is translated by your compilers into a call to the mangled name of that function, so when you write <NOBR>this,<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>
<A NAME="36689"></A>
<UL><PRE>drawLine(a, b, c, d); // call to unmangled function name
</PRE>
</UL><A NAME="36690"></A>
<P><A NAME="dingp9"></A>your object files contain a function call that corresponds to <NOBR>this:<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>
<A NAME="36691"></A>
<UL><PRE>xyzzy(a, b, c, d); // call to mangled function mame
</PRE>
</UL><A NAME="36695"></A>
<P><A NAME="dingp10"></A>
But if <CODE>drawLine</CODE> is a C function, the object file (or archive or dynamically linked library, etc.) that contains the compiled version of <CODE>drawLine</CODE> contains a function called <CODE><I>drawLine</I></CODE>; no name mangling has taken place. When you try to link the object files comprising your program together, you'll get an error, because the linker is looking for a function called <CODE>xyzzy</CODE>, and there is no such <NOBR>function.<SCRIPT>create_link(10);</SCRIPT>
</NOBR></P><A NAME="86045"></A>
<P><A NAME="dingp11"></A>
To solve this problem, you need a way to tell your C++ compilers not to mangle certain function names. You never want to mangle the names of functions written in other languages, whether they be in C, assembler, FORTRAN, Lisp, Forth, or what-have-you. (Yes, what-have-you <A NAME="p272"></A>would include COBOL, but then what would you have?) After all, if you call a C function named <CODE>drawLine</CODE>, it's really called <CODE>drawLine</CODE>, and your object code should contain a reference to that name, not to some mangled version of that <NOBR>name.<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P><A NAME="36738"></A>
<P><A NAME="dingp12"></A>
To suppress name mangling, use C++'s <CODE>extern</CODE> <CODE>"C"</CODE> <NOBR>directive:<SCRIPT>create_link(12);</SCRIPT>
</NOBR></P>
<A NAME="36743"></A>
<UL><PRE>// declare a function called drawLine; don't mangle
// its name
extern "C"
void drawLine(int x1, int y1, int x2, int y2);
</PRE>
</UL><A NAME="36741"></A>
<P><A NAME="dingp13"></A>
Don't be drawn into the trap of assuming that where there's an <CODE>extern</CODE> <CODE>"C"</CODE>, there must be an <CODE>extern</CODE> <CODE>"Pascal"</CODE> and an <CODE>extern</CODE> <CODE>"FORTRAN"</CODE> as well. There's not, at least not in <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=cstandard" onMouseOver="self.status='C++ Language Standard Home Page'; return true" onMouseOut="self.status = self.defaultStatus" target="_top">the</NOBR> standard</A>. The best way to view <CODE>extern "C"</CODE> is not as an assertion that the associated function is written in C, but as a statement that the function should be called as if it <i>were</i> written in C. (Technically, <CODE>extern</CODE> <CODE>"C"</CODE> means the function has C linkage, but what that means is far from clear. One thing it always means, however, is that name mangling is <NOBR>suppressed.)<SCRIPT>create_link(13);</SCRIPT>
</NOBR></P><A NAME="73253"></A>
<P><A NAME="dingp14"></A>
For example, if you were so unfortunate as to have to write a function in assembler, you could declare it <CODE>extern</CODE> <CODE>"C"</CODE>, <NOBR>too:<SCRIPT>create_link(14);</SCRIPT>
</NOBR></P>
<A NAME="36754"></A>
<UL><PRE>// this function is in assembler — don't mangle its name
extern "C" void twiddleBits(unsigned char bits);
</PRE>
</UL><A NAME="36732"></A>
<P><A NAME="dingp15"></A>
You can even declare C++ functions <CODE>extern</CODE> <CODE>"C"</CODE>. This can be useful if you're writing a library in C++ that you'd like to provide to clients using other programming languages. By suppressing the name mangling of your C++ function names, your clients can use the natural and intuitive names you choose instead of the mangled names your compilers would otherwise <NOBR>generate:<SCRIPT>create_link(15);</SCRIPT>
</NOBR></P>
<A NAME="36755"></A>
<UL><PRE>// the following C++ function is designed for use outside
// C++ and should not have its name mangled
extern "C" void simulate(int iterations);
</PRE>
</UL><A NAME="36733"></A>
<P><A NAME="dingp16"></A>
Often you'll have a slew of functions whose names you don't want mangled, and it would be a pain to precede each with <CODE>extern</CODE> <CODE>"C"</CODE>. Fortunately, you don't have to. <CODE>extern</CODE> <CODE>"C"</CODE> can also be made to apply to a whole set of functions. Just enclose them all in curly <NOBR>braces:<SCRIPT>create_link(16);</SCRIPT>
</NOBR></P>
<A NAME="36756"></A>
<UL><PRE>extern "C" { // disable name mangling for
// all the following functions
<A NAME="36761"></A>
void drawLine(int x1, int y1, int x2, int y2);
void twiddleBits(unsigned char bits);
void simulate(int iterations);
...<A NAME="36773"></A>
}</PRE>
</UL>
<A NAME="36823"></A><A NAME="p273"></A>
<P><A NAME="dingp17"></A>
This use of <CODE>extern</CODE> <CODE>"C"</CODE> simplifies the maintenance of header files that must be used with both C++ and C. When compiling for C++, you'll want to include <CODE>extern</CODE> <CODE>"C"</CODE>, but when compiling for C, you won't. By taking advantage of the fact that the preprocessor symbol <CODE>__cplusplus</CODE> is defined only for C++ compilations, you can structure your polyglot header files as <NOBR>follows:<SCRIPT>create_link(17);</SCRIPT>
</NOBR></P>
<A NAME="36843"></A>
<UL><PRE>#ifdef __cplusplus
<A NAME="36844"></A>
extern "C" {
<A NAME="36845"></A>
#endif
<A NAME="36846"></A>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -