⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch13.htm

📁 c++语言操作手册
💻 HTM
📖 第 1 页 / 共 4 页
字号:
  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 &lt;iostream&gt; Classes with &lt;stdio.h&gt;   Functions</a></h2><p>It is possible to use both <tt>&lt;iostream&gt;</tt> classes and <tt>&lt;stdio.h&gt;</tt>   library functions in the same program, as long as they do not access the same   file. For example, you can use the <tt>&lt;iostream&gt;</tt> object <tt>cin</tt>   to read data from the keyboard, and then use <tt>&lt;stdio.h&gt;</tt> functions   to write the data to a disk file, as in the following program:</p><pre><tt>#include &lt;iostream&gt;</tt><tt>#include &lt;cstdio&gt;</tt><tt>using namespace std;</tt><tt>int main()</tt><tt>{</tt><tt>  int num;</tt><tt>  cin&gt;&gt;num;</tt><tt>  cout&lt;&lt;"you enetred: "&lt;&lt; num &lt;&lt;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>&lt;iostream&gt;</tt> and <tt>&lt;stdio.h&gt;</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>&lt;iostream&gt;</tt>   and <tt>&lt;stdio.h&gt;</tt> access the same file. For example</p><pre><tt>#include &lt;iostream&gt;</tt><tt>#include &lt;cstdio&gt;</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&gt;&gt;num;</tt><tt>  cout&lt;&lt;"you enetred: "&lt;&lt; num &lt;&lt; "please enter another one " &lt;&lt; endl;</tt><tt>  scanf("%d", &amp;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>&lt;stdio.h&gt;</tt> and C++ objects that use   <tt>&lt;iostream&gt;</tt>, I/O synchronization is unavoidable because, ultimately,   the same low-level system resources are used by both <tt>&lt;stdio.h&gt;</tt>   and <tt>&lt;iostream&gt;</tt>.</p><p>The fact that <tt>&lt;iostream&gt;</tt> and <tt>&lt;stdio.h&gt;</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><tt>  int year;</tt><tt>  //constructor and destructor</tt><tt>  Date(); //current date</tt>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -