📄 index.html
字号:
have to share data and code with one another. This section focuses on how to
combine C and C++ code in a bilingual system that uses both these languages
simultaneously.</p>
<p>The easiest way to ensure compatibility between code modules that are written
in C and C++ is to adhere to the common denominator of these languages. Then
again, using C++ as a procedural language ("better C") isn't worth the bother
-- you can simply stick to C. Combining object-oriented C++ code with procedural
C code into a seamless executable is more challenging -- but it offers many
advantages.</p>
<h2> <a name="Heading24">C and C++ Linkage Conventions</a></h2>
<p>By default, C++ functions have C++ linkage, which is incompatible with C linkage.
Consequently, global C++ functions cannot be called from C code unless they
are explicitly declared as having a C linkage.</p>
<h3> <a name="Heading25">Forcing C Linkage on A C++ Function</a></h3>
<p>To override the default C++ linkage, a C++ function has to be declared <tt>extern
"C"</tt>.For example</p>
<pre>
<tt>// filename decl.hpp</tt>
<tt><b>extern "C"</b> void f(int n); //force C linkage so that f() can be called from C</tt>
<tt> // code although it is compiled by a C++ compiler</tt>
<tt> // decl.hpp</tt>
</pre>
<p>The <tt>extern "C"</tt> prefix instructs a C++ compiler to apply C linkage
to the function <tt>f()</tt> rather than the default C++ linkage. This means
that a C++ compiler does not apply <i>name mangling</i> to <tt>f()</tt>, either
(see the following sidebar, "What's in Name Mangling?"). Consequently, a call
to <tt>f()</tt> from C code is properly resolved by a C linker. A C++ linker
can also locate the compiled version of <tt>f()</tt> even though it has a C
linkage type. In other words, declaring C++ functions as <tt>extern "C"</tt>
guarantees interoperability between C++ and C (as well as other procedural languages
that use the C calling convention). However, forcing C linkage has a price:
It is impossible to overload another version of <tt>f()</tt> that is also declared
as <tt>extern "C"</tt>. For example</p>
<pre>
<tt>// filename decl.hpp</tt>
<tt>extern "C" void f(int n);</tt>
<tt>extern "C" void f(float f); //error, second C linkage of f is illegal</tt>
<tt>// decl.hpp</tt>
</pre>
<p>Note that you can declare additional overloaded versions of <tt>f()</tt> as
long as they are not declared <tt>extern "C"</tt>:</p>
<pre>
<tt>// filename decl.hpp</tt>
<tt>extern "C" void f(int n); //OK, can be called from C and C++ code</tt>
<tt>void f(float f); //OK, no C linkage used. Can be called only from C++ code</tt>
<tt>void f(char c); //OK, no C linkage used. Can be called only from C++ code</tt>
<tt>// decl.hpp</tt>
</pre>
<p>How does it work? A call to the function from C code is translated to a <cite>CALL</cite>
assembly directive, followed by the function name. Declaring a C++ function
as <tt>extern "C"</tt> ensures that the name that is generated for it by a C++
compiler is identical to the name that a C compiler expects. On the other hand,
if the called function is compiled by a C++ compiler without the <tt>extern
"C"</tt> specifier, it has a mangled name but a C compiler still places the
nonmangled name after the <tt>CALL</tt> directive, resulting in a link-time
error.</p>
<blockquote>
<hr>
<b>What's in Name Mangling?<br>
</b>Name mangling (the more politically correct term, although rarely used,
is <i>name decoration</i>) is a method used by a C++ compiler to generate unique
names for identifiers in a program. The exact details of the algorithm are compiler-dependent,
and they might vary from one version to another. Name mangling ensures that
entities with seemingly identical names get unique identifications. The resultant
mangled name contains all the information that might be needed by the linker,
including linkage type, scope, calling convention, and so on. For instance,
when a global function is overloaded, the generated mangled name for each overloaded
version is unique. Name mangling is also applied to variables. Thus, a local
variable and a global variable with the same user-given name still get distinct
mangled names. How is the mangled name synthesized? The compiler picks the user-given
name of an identifier and decorates it with additional affixes to indicate a
variable of a fundamental type, a class, or a function. For a function, the
mangled name embeds its scope and linkage type, the namespace in which it is
declared, the list of parameters, the parameters' passing mechanism, and the
parameters' cv-qualifications. A mangled name of a member function incorporates
additional information such as the class name, whether it is a <tt>const</tt>
member function, and other implementation-dependent details that the linker
and the runtime environment might need. Following is an example: For a global
function <tt>void func(int);</tt>, a given compiler can generate the corresponding
mangled name <tt>__x_func@i@</tt>, where the affix <tt>x</tt> indicates a function,
<tt>func</tt> is the function's user-given name, <tt>@</tt> indicates the beginning
of the parameter list, <tt>i</tt> indicates the type of the parameter, and the
closing <tt>@</tt> sign signals the end of the parameter list. An overloaded
version of <tt>f()</tt> has a different mangled name because it has a different
parameter list. The original user-given name can be reproduced from the mangled
name, so linkers in general can issue error messages in a human-readable format.
<br>
<br>
As was previously stated, the name mangling scheme of a given compiler can change
from one version to another (for example, if the new version supports namespaces,
whereas the previous one did not). This is one of the reasons you often have
to recompile your code with every compiler upgrade. Another important implication
is that, usually, the linker and the compiler need to come from the same vendor
and have compatible versions. This ensures that they share the same naming conventions
and that they produce compatible binary code.
<hr>
</blockquote>
<h3> <a name="Heading26">Calling C++ Code from C Code</a></h3>
<p>Up until now, you have observed the C++ side of the story. A C program cannot
<tt>#include</tt> the header file <tt>decl.hpp</tt> because the <tt>extern "C"</tt>
specifier is not recognized by a C compiler. To ensure that the declaration
can be parsed by a C compiler, <tt>extern "C"</tt> needs to be visible to a
C++ compiler -- but not to a C compiler. A C++ function with C linkage has to
be declared in two distinct forms, one for C++ and another for C. This can be
achieved by using separate C and C++ header files. The C header file looks similar
to the following:</p>
<pre>
<tt>/*** filename decl.h ***/</tt>
<tt>void f(int n); /* identical to the C++ header but no extern "C" here */</tt>
<tt> /*** decl.h ***/</tt>
</pre>
<p>The header file can be <tt>#included</tt> in the C source file that calls the
function <tt>f()</tt>. For example</p>
<pre>
<tt>/*** filename do_something.c ***/</tt>
<tt>#include "decl.h"</tt>
<tt>void do_something()</tt>
<tt>{</tt>
<tt> f(5);</tt>
<tt>}</tt>
<tt>/*** do_something.c ***/</tt>
</pre>
<p>Keeping separate header files for C and C++ is not an elegant solution, however.
The header files have to remain in sync all the time, and when many header files
are used, this can turn into a serious maintenance problem. A better alternative
is to use one or more C header files for the declarations. For example</p>
<pre>
<tt>/*** filename f.h ***/</tt>
<tt>void f(int n); /* identical to the C++ header but no extern "C" here */</tt>
<tt> /*** f.h ***/</tt>
<tt>/*** filename g.h ***/</tt>
<tt>void g(const char * pc, int n); </tt>
<tt> /*** g.h ***/</tt>
</pre>
<p>Next, the C header files are <tt>#included</tt> in a C++ header file that contains
an <tt>extern "C"</tt> block:</p>
<pre>
<tt>// filename decl.hpp</tt>
<tt>extern "C"</tt>
<tt>{</tt>
<tt>#include "f.h"</tt>
<tt>#include "g.h"</tt>
<tt>}</tt>
<tt>// filename decl.hpp</tt>
</pre>
<p>The effect of an <tt>extern "C"</tt> block is as if every declaration in the
<tt>#included</tt> header files had a preceding <tt>extern "C"</tt> specifier.
Another alternative is to modify the C header file directly by adding an <tt>#ifdef</tt>
directive to make the <tt>extern "C"</tt> declaration visible only to a C++
compiler. For example</p>
<pre>
<tt>/*** filename decl.h ***/</tt>
<tt>#ifdef __cplusplus</tt>
<tt>extern "C" { //visible only to a C++ compiler</tt>
<tt>#endif</tt>
<tt>void g(const char * pc, int n);</tt>
<tt>void f(int n);</tt>
<tt>#ifdef __cplusplus</tt>
<tt>} //visible only to a C++ compiler</tt>
<tt>#endif</tt>
<tt> /*** g.h ***/</tt>
</pre>
<p>This way, only one header file is needed. However, it is not always possible
to modify the C header files directly. In such cases, the preceding technique
needs to be used. Please note that a C++ function called from C code is an ordinary
C++ function. It can instantiate objects, invoke their member functions, or
use any other C++ feature. However, some implementations might require special
configuration settings to ensure that the linker has access to the C++ libraries
and template codes.</p>
<h3> <a name="Heading27">Compiling main()</a></h3>
<p>Functions can be compiled by either a C compiler or a C++ compiler. However,
a C++ compiler should compile <tt>main()</tt>. This enables a C++ compiler to
take care of templates, static initialization, and additional implementation-dependent
operations for which <tt>main()</tt> is responsible. Compiling <tt>main()</tt>
under a C compiler will most likely result in link-time errors due to the different
semantics of <tt>main()</tt> in C and C++.</p>
<h2> <a name="Heading28">Minimize the Interface Between C and C++ Code</a></h2>
<p>In general, you can call a C function from C++ code without special adjustments.
The opposite, as you have seen, is also possible -- but it requires additional
adjustments. It is therefore recommended that you keep the interface between
the two languages at a minimum. Declaring every C++ function as <tt>extern "C"</tt>,
for example, is not recommended. Not only does this convention imply additional
modifications to the header files, it also disables overloading. Remember also
that you cannot declare a member function <tt>extern "C".</tt> For C++ functions
that have to be called from C code, it might be advantageous to use a function
wrapper that has an <tt>extern "C"</tt> specifier. In this case, the wrapped
C++ functions can have the C++ linkage. For example</p>
<pre>
<tt>void g(const char * pc, int n); //extern "C" is unnecessary</tt>
<tt>void f(int n);</tt>
<tt>extern "C" void f_Wrapper(int n) //only the wrapper function is called from C</tt>
<tt>{</tt>
<tt> f(n);</tt>
<tt>}</tt>
<tt>extern "C" void g_Wrapper(const char *pc, int n)</tt>
<tt>{</tt>
<tt> g(pc, n);</tt>
<tt>}</tt>
</pre>
<h2> <a name="Heading29">Mixing <iostream> Classes with <stdio.h>
Functions</a></h2>
<p>It is possible to use both <tt><iostream></tt> classes and <tt><stdio.h></tt>
library functions in the same program, as long as they do not access the same
file. For example, you can use the <tt><iostream></tt> object <tt>cin</tt>
to read data from the keyboard, and then use <tt><stdio.h></tt> functions
to write the data to a disk file, as in the following program:</p>
<pre>
<tt>#include <iostream></tt>
<tt>#include <cstdio></tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> int num;</tt>
<tt> cin>>num;</tt>
<tt> cout<<"you enetred: "<< num <<endl;</tt>
<tt> FILE *fout = fopen("data.dat", "w");</tt>
<tt> if (fout) //write num to a disk file</tt>
<tt> {</tt>
<tt> fprintf(fout, "%d\n", num);</tt>
<tt> }</tt>
<tt> fclose(fout);</tt>
<tt> return 0;</tt>
<tt>}</tt>
</pre>
<p>It is even possible to use <tt><iostream></tt> and <tt><stdio.h></tt>
to manipulate the same file; for instance, a program can send output to both
<tt>stdout</tt> and <tt>cout</tt>, although this is not recommended. To enable
simultaneous access to the same file, you first have to call <tt>ios::sync_with_stdio(true);</tt>
to synchronize the I/O operations. Note, however, that this synchronization
degrades performance. Therefore, only use it when <tt><iostream></tt>
and <tt><stdio.h></tt> access the same file. For example</p>
<pre>
<tt>#include <iostream></tt>
<tt>#include <cstdio></tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> ios::sync_with_stdio(true);//enable mixed I/O</tt>
<tt> int num;</tt>
<tt> printf("please enter a number\n");</tt>
<tt> cin>>num;</tt>
<tt> cout<<"you enetred: "<< num << "please enter another one " << endl;</tt>
<tt> scanf("%d", &num);</tt>
<tt> return 0;</tt>
<tt>}</tt>
</pre>
<p>Normally, you won't write such code. However, when a large application combines
legacy C functions that use <tt><stdio.h></tt> and C++ objects that use
<tt><iostream></tt>, I/O synchronization is unavoidable because, ultimately,
the same low-level system resources are used by both <tt><stdio.h></tt>
and <tt><iostream></tt>.</p>
<p>The fact that <tt><iostream></tt> and <tt><stdio.h></tt> can be
combined is a major advantage. Otherwise, the migration process from C to C++
might be much fussier, and making C and C++ code work together might prove to
be very difficult.</p>
<h2> <a name="Heading30">Accessing a C++ Object in C Code</a></h2>
<p>Can C code, which of course is unaware of object semantics, access the data
members of a C++ object directly? The short answer is, "Yes, but". There are
some guarantees about the underlying memory layout of an object; C code can
take advantage of these guarantees and treat a C++ object as an ordinary data
struct, provided that all the following restrictions apply to the class of the
object in question:</p>
<ul>
<li>
<p> The class has no virtual member functions (including inherited virtual
functions of a base class).</p>
</li>
<p></p>
<li>
<p> The class has no virtual base classes in the entire inheritance chain.</p>
</li>
<p></p>
<li>
<p> The class has no member objects that have either a virtual base class
or virtual member functions.</p>
</li>
<p></p>
<li>
<p> All the data members of the class are declared without an intervening
access specifier. </p>
</li>
</ul>
<p></p>
<h3> <a name="Heading31">The Underlying Representation of an Object in Memory</a></h3>
<p>Examine these restrictions in more detail, given the following declaration
of the class <tt>Date</tt>:</p>
<pre>
<tt>class Date</tt>
<tt>{</tt>
<tt>public:</tt>
<tt> int day;</tt>
<tt> int month;</tt>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -