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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 1 页 / 共 4 页
字号:
<h3> <a name="Heading13">Definition of Structs in a Function Parameter List and 
  Return Type</a></h3>
<p>In C, a struct can be defined in a function parameter list as well as in its 
  return type. For example</p>
<pre>
<tt>/*** valid in C but not C++ ***/</tt>
<tt>/* struct definition in return type and parameter list of a function */</tt>
<tt>struct Stat { int code; char msg[10];} </tt>
<tt>    logon (struct User { char username[8];  char pwd[8];} u );</tt>
</pre>
<p>In C++, this is illegal.</p>
<h3> <a name="Heading14">Bypassing an Initialization</a></h3>
<p>A <i>jump statement</i> unconditionally transfers control. A jump statement 
  is one of the following: a <tt>goto</tt> statement, a transfer from the condition 
  of a <tt>switch</tt> statement to a <tt>case</tt> label, a <tt>break</tt> statement, 
  a <tt>continue</tt> statement, or a <tt>return</tt> statement. In C, the initialization 
  of a variable can be skipped by a jump statement, as in the following example:</p>
<pre>
<tt>/*** valid in C but not C++ ***/</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  int n=1;</tt>
<tt>  switch(n)</tt>
<tt>  {</tt>
<tt>  case 0:</tt>
<tt>    int j=0;</tt>
<tt>    break;</tt>
<tt>  case 1: /* skip initialization of j */</tt>
<tt>    j++;  /* undefined */</tt>
<tt>    break;</tt>
<tt>  default:</tt>
<tt>    break;</tt>
<tt>  }</tt>
<tt>  return 0;</tt>
<tt>}</tt>
</pre>
<p>In C++, bypassing an initialization is illegal.</p>
<h2> <a name="Heading15">Quiet Differences Between C and C++</a></h2>
<p>The differences that have been presented thus far are easily diagnosed by a 
  C++ compiler. There are, however, semantic differences between C and C++ in 
  the interpretation of certain constructs. These differences might not result 
  in a compiler diagnostic; therefore, it is important to pay attention to them.</p>
<h3> <a name="Heading16">The Size of an enum Type</a></h3>
<pre>
<tt>In C, the size of an enumeration equals the sizeof(int). In C++, the underlying type for an enumeration is not necessarily an int -- it can be smaller. Furthermore, if an enumerator's value is too large to be represented as an unsigned int, the implementation is allowed to use a larger unit. For example enum { SIZE = 5000000000UL };</tt>
</pre>
<h3> <a name="Heading17">The Size of A Character Constant</a></h3>
<p>In C, the result of applying the operator <tt>sizeof</tt> to a character constant 
  -- for example, <tt>sizeof('c');</tt> -- equals <tt>sizeof(int)</tt>. In C++, 
  on the other hand, the expression <tt>sizeof('c');</tt> equals <tt>sizeof(char)</tt>.</p>
<h3> <a name="Heading18">Predefined Macros</a></h3>
<p>C and C++ compilers define the following macros: </p>
<pre>
<tt>__DATE__ /*a literal containing compilation date in the form "Apr 13 1998" */</tt>
<tt>__TIME__ /*a literal containing the compilation time in the form "10:01:07" */</tt>
<tt>__FILE__  /*a literal containing the name of the source file being compiled */</tt>
<tt>__LINE__ /* current line number in the source file */</tt>
</pre>
<p>C++ compilers exclusively define the following macro:</p>
<pre>
<tt>__cpluplus</tt>
</pre>
<p>Standard-compliant C compilers define the following macro symbol:</p>
<pre>
<tt>__STDC__</tt>
</pre>
<p>Whether a C++ compiler also defines the macro symbol <tt>__STDC__</tt> is implementation-dependent.</p>
<h3> <a name="Heading19">Default Value Returned from main()</a></h3>
<p>In C, when control reaches the end of <tt>main()</tt> without encountering 
  a <tt>return</tt> statement, the effect is that of returning an undefined value 
  to the environment. In C++, however, <tt>main()</tt> implicitly executes a</p>
<pre>
<tt>return 0;</tt>
</pre>
<p>statement in this case.</p>
<blockquote>
  <hr>
  <strong>NOTE: </strong> You might have noticed that the code listings throughout 
  the book contain an explicit <tt>return</tt> statement at the end of <tt>main()</tt>, 
  even though this is not necessary. There are two reasons for this: First, many 
  compilers that do not comply with the Standard issue a warning message when 
  a <tt>return</tt> statement is omitted. Secondly, the explicit <tt>return</tt> 
  statement is used to return a nonzero value in the event of an error. 
  <hr>
</blockquote>
<h2> <a name="Heading20">Migrating From C to C++</a></h2>
<p>Resolving the syntactic and semantic differences between C and C++ is the first 
  step in migrating from C to C++. This process ensures that C code can compile 
  under a C++ compiler, and that the program behaves as expected. There is another 
  clear advantage of compiling C code under a C++ compiler: The tighter type checking 
  that is applied by a C++ compiler can detect potential bugs that a C compiler 
  does not detect. The list of discrepancies between C and C++ that was previously 
  presented is mostly a result of loopholes and potential traps in C that were 
  fixed in C++. An issue that is of concern, however, is performance -- does a 
  C++ compiler produce object code that is less efficient than the code produced 
  by a C compiler? This topic is discussed in more detail in Chapter 12, "Optimizing 
  Your Code." However, it is important to note that a good C++ compiler can <i>outperform</i> 
  a good C compiler because it can exercise optimization techniques that C compilers 
  normally do not support, such as function inlining and the <i>named return value</i> 
  (also discussed in Chapter 12).</p>
<p>Nonetheless, in order to benefit from the robustness of object-oriented programming, 
  more substantial code modifications are required. Fortunately, the transition 
  from procedural to object-oriented programming can be performed gradually. The 
  following section demonstrates a technique of wrapping bare functions with an 
  additional code layer to minimize the dependency on implementation details. 
  Following that is a discussion of how to use full-fledged classes that wrap 
  legacy code in order to gain more of the benefits of object-orientation.</p>
<h3> <a name="Heading21">Function Wrappers</a></h3>
<p>Low-level code such as infrastructure routines and API functions can be used 
  by different teams for the same project. Normally, this code is developed and 
  maintained by a third party vendor or a specific team in the project. For example</p>
<pre>
<tt>int retrievePerson (int key, Person* recordToBefilled); /* C function */</tt>
</pre>
<p>A problem can arise when the interface of <tt>()</tt> changes: Every occurrence 
  of a function call has to be tracked down and modified accordingly. Consider 
  how such a small change can affect existing programs:</p>
<pre>
<tt>/*</tt>
<tt> function modification: key is now a char * instead of an int</tt>
<tt> every call to this function has to modified accordingly</tt>
<tt>*/</tt>
<tt>int retrievePerson (const char * key, Person* recordToBefilled);</tt>
</pre>
<p>As you saw in Chapter 5, "Object-Oriented Programming and Design," one of the 
  most noticeable weaknesses of procedural programming is its vulnerability to 
  such changes; however, even in strict procedural programming you can localize 
  their impact by using a <i>wrapper function</i>. A wrapper function calls the 
  vulnerable function and returns its result. Following is an example:</p>
<pre>
<tt>/* A wrapper function */</tt>
<tt>int WrapRetrievePerson(int key, Person* recordToBefilled)</tt>
<tt>{</tt>
<tt>  return retrievePerson (key, recordToBefilled);</tt>
<tt>}</tt>
</pre>
<p>A wrapper provides a stable interface to a code fragment that is used extensively 
  and that is vulnerable to changes. When using a wrapper function, a change in 
  the interface of an API function is reflected only in the definition of its 
  corresponding wrapper function. Other parts of the program are not affected 
  by the change. This is very similar to the way in which a class's accessors 
  and mutators provide indirect access to its nonpublic members. In the following 
  example, the function wrapper's body has been modified due to the change in 
  the type of key from <tt>int</tt> to <tt>char *</tt>. Note, however, that its 
  interface remains intact:</p>
<pre>
<tt>/*** file DB_API.h ***/</tt>
<tt>int retrievePerson (const char *strkey, Person* precordToBefilled);</tt>
<tt>typedef struct</tt>
<tt>{</tt>
<tt>  char first_name[20];</tt>
<tt>  char last_name[20];</tt>
<tt>  char address [50];</tt>
<tt>} Person;</tt>
<tt>/*** file DB_API.h ***/</tt>
<tt>#include &lt;stdio.h&gt;</tt>
<tt>#include " DB_API.h "</tt>
<tt>int WrapRetrievePerson(int key, Person* precordToBefilled) //remains intact</tt>
<tt>{</tt>
<tt>  /* wrapper's implementation modified according to API's modification */</tt>
<tt>  char strkey[100];</tt>
<tt>  sprintf (strkey, "%d", key);  /* convert int to a string */</tt>
<tt>  return retrievePerson (strkey, precordToBefilled);</tt>
<tt>}</tt>
</pre>
<p>By systematically applying this technique to every function that is maintained 
  by other teams or vendors, you can ensure a reasonable level of interface stability 
  even when the underlying implementation changes.</p>
<p>Although the function wrapper technique offers protection from changes in implementation 
  details, it does not provide other advantages of object-oriented programming, 
  including encapsulation of related operations in a single class, constructors 
  and destructors, and inheritance. The next phase in the migration process is 
  to encapsulate a collection of related functions into a single wrapper class. 
  This technique, however, requires familiarity with object-oriented concepts 
  and principles.</p>
<h2> <a name="Heading22">Designing Legacy Code Wrapper Classes</a></h2>
<p>In many frameworks that were originally written in C and then ported to C++, 
  a common -- but wrong -- practice was to wrap C functions in a single <i>wrapper 
  class</i>. Such a wrapper class provides as its interface a series of operations 
  mapped directly to the legacy functions. The following networking functions 
  provide an example:</p>
<pre>
<tt>/*** file: network.h ***/</tt>
<tt>#ifndef NETWORK_H</tt>
<tt>#define NETWORK_H</tt>
<tt>    /* functions related to UDP protocol */</tt>
<tt>int UDP_init();</tt>
<tt>int UDP_bind(int port);</tt>
<tt>int UDP_listen(int timeout);</tt>
<tt>int UDP_send(char * buffer);</tt>
<tt>    /* functions related to X.25 protocol */</tt>
<tt>int X25_create_virtual_line();</tt>
<tt>int X25_read_msg_from_queue(char * buffer);</tt>
<tt>    /* general utility functions */</tt>
<tt>int hton(unsigned int); //reverse bytes from host to network order</tt>
<tt>int ntoh(unsigned int); //reverse bytes from network to host order</tt>
<tt>#endif</tt>
<tt>/*** network.h ***/</tt>
</pre>
<p>A na[um]ive implementation of a class wrapper might simply embed all these 
  functions in a single class as follows:</p>
<pre>
<tt>#include "network.h"</tt>
<tt>class Networking</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>//...stuff</tt>
<tt>public:</tt>
<tt>  //constructor and destructor</tt>
<tt>  Networking();</tt>
<tt>  ~Networking();</tt>
<tt>  //members</tt>
<tt>  int UDP_init();</tt>
<tt>  int UDP_bind(int port);</tt>
<tt>  int UDP_listen(int timeout);</tt>
<tt>  int UDP_send(char * buffer);</tt>
<tt>  int X25_create_virtual_line();</tt>
<tt>  int X25_read_msg_from_queue(char * buffer);</tt>
<tt>  int hton(unsigned int); //reverse bytes from host to network order</tt>
<tt>  int ntoh(unsigned int); //reverse bytes from network to host order</tt>
<tt>};</tt>
</pre>
<p>However, this method of implementing a wrapper class is not recommended. X.25 
  and UDP protocols are used for different purposes and have almost nothing in 
  common. Bundling the interfaces of these two protocols together can cause maintenance 
  problems in the long term -- and it undermines the very reason for moving to 
  an object-oriented design in the first place. Furthermore, due to its amorphous 
  interface, <tt>Networking</tt> is not an ideal base for other derived classes.The 
  problem with <tt>Networking</tt> and similar classes is that they do not genuinely 
  embody an object-oriented policy. They are merely a collection of unrelated 
  operations. A better design approach is to divide the legacy functions into 
  meaningful, self-contained units and wrap each unit by a dedicated class. For 
  example</p>
<pre>
<tt>#include "network.h"</tt>
<tt>class UDP_API</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>//...stuff</tt>
<tt>public:</tt>
<tt>  //constructor and destructor</tt>
<tt>  UDP_API();</tt>
<tt>  ~UDP_API();</tt>
<tt>  //members</tt>
<tt>  int UDP_init();</tt>
<tt>  int UDP_bind(int port);</tt>
<tt>  int UDP_listen(int timeout);</tt>
<tt>  int UDP_send(char * buffer);</tt>
<tt>};</tt>
<tt>class X25_API</tt>
<tt>{</tt>
<tt>private:</tt>
<tt>//...stuff</tt>
<tt>public:</tt>
<tt>  //constructor and destructor</tt>
<tt>  X25_API();</tt>
<tt>  ~X25_API();</tt>
<tt>  //members</tt>
<tt>  int X25_create_virtual_line();</tt>
<tt>  int X25_read_msg_from_queue(char * buffer);</tt>
<tt>};</tt>
<tt>class Net_utility</tt>
<tt>{</tt>
<tt>    private:</tt>
<tt>//...stuff</tt>
<tt>public:</tt>
<tt>  //constructor and destructor</tt>
<tt>  Net_utility();</tt>
<tt>  ~Net_utility();</tt>
<tt>  //members</tt>
<tt>  int hton(unsigned int); //reverse bytes from host to network order</tt>
<tt>  int ntoh(unsigned int); //reverse bytes from network to host order</tt>
<tt>};</tt>
</pre>
<p>Now each class offers a coherent interface. Another advantage is a simpler 
  usage protocol; users of class <tt>X25_API</tt>, for instance, are not forced 
  to accept the interface of UDP protocol, and vice versa.</p>
<h2> <a name="Heading23">Multilingual Environments</a></h2>
<blockquote>
  <hr>
  <strong>NOTE: </strong> In this section, the distinction between C code and 
  C++ is indicated explicitly by file extensions. The .h extension is used for 
  C header files, whereas C++ header files are indicated by the .hpp extension. 
  Similarly, .c and .cpp extensions are used for C and C++ source files, respectively. 
  In addition, only C-style comments are used in C files. 
  <hr>
</blockquote>
<p>Thus far, this chapter has concentrated on a unidirectional migration process: 
  from C to C++. Nevertheless, many systems are not confined to a single programming 
  language. A typical information system can simultaneously use one programming 
  language for the graphical interface, another language for accessing data from 
  a database, and a third language for server applications. Often, these languages 

⌨️ 快捷键说明

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