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

📄 第14章 程序的文件结构.htm

📁 用非常通俗的语言介绍了C++和C
💻 HTM
📖 第 1 页 / 共 4 页
字号:
      <P>#endif</P>
      <P> </P>
      <P>和源文件中新增代码添加在最后不一样,头文件中新加代码 
      必须在#endif之前插入。所以本例中,加完函数声明的代码应如其下所示。(另外,CB总是在头文件的第二行留了一行空白行,我不知道它这是有意还是无意。总之这里是我们写本文件总体注释的好地方。记住,头文件像名片,用于让别人看,很有必要写得详细点)</P>
      <P>//---------------------------------------------------------------------------<BR>&nbsp;&nbsp; 
      <B>//主要操作函数</B></P>
      <P>#ifndef mainfuncH </P>
      <P>#define mainfuncH </P>
      <P>//--------------------------------------------------------------------------- 
      </P>
      <P><B>//计算总和:</B></P>
      <P><B>void CalcTotal(int n);</B></P>
      <P><B>//计算平均值:</B></P>
      <P><B>void CalcAverage(int n);</B></P>
      <P><B>//--------------------------------------------------------------------------- 
      </B></P>
      <P>#endif</P>
      <P> </P>
      <P>这就是“在头文件中声明函数”的整个过程。下面是另外一个头文件。</P>
      <P> </P>
      <P><B>头文件:mainfunc.h</B></P>
      <P>//--------------------------------------------------------------------------- 
      </P>
      <P><B>//辅助操作函数 </B></P>
      <P>#ifndef assifuncH </P>
      <P>#define assifuncH </P>
      <P>//--------------------------------------------------------------------------- 
      </P>
      <P><B>//将字符转换成大写 </B></P>
      <P><B>char ToUpper(char c); </B></P>
      <P>#endif</P>
      <P> </P>
      <P>今天我们学的是如何在头文件内声明函数,以后我们需要在头文件内声明变量,或者定义新的数据类型,它们都一样需要在上述的#endif之前加入。</P>
      <P> </P>
      <H4><A name=14.3.2>14.3.2</A> 最常见的预编译语句</H4>
      <P> </P>
      <P>现在来解释这三行话:</P>
      <P>#ifndef mainfuncH </P>
      <P>#define mainfuncH </P>
      <P> </P>
      <P>#endif</P>
      <P> </P>
      <P>中间的 #define mainfuncH 我们有点脸熟。在第五章《变量与常量》中,我们讲过用<A 
      href="http://www.d2school.com/bcyl/bhcpp/newls/ls05.htm#5.3.2">宏表示常数</A>。语法为:</P>
      <P>#define 宏名称 宏值</P>
      <P> </P>
      <P>比如,定义一个∏值:</P>
      <P>#define PAI 3.14159 </P>
      <P> </P>
      <P>这里我们学的是宏定义的另一种用法:仅仅定义一个宏,不需要给出它的值,语法为:</P>
      <P> </P>
      <P>#define 宏名称</P>
      <P> </P>
      <P>比如:#define mainfuncH</P>
      <P> </P>
      <P>定义了一个宏:mainfuncH。如果你无法理解“宏”这个词,不妨就当把它解释成“记号”。即编译器通过该语句,做了一个记号,记号名称为:mainfucH。</P>
      <P>这么做的作用是什么呢?我们继续看上下文。</P>
      <P> </P>
      <P>#ifndef 中, if 是“如果”,n 是 no,即“还没有”,def是 define,即“定义”,那么:</P>
      <P>#ifndef mainfuncH 意为:“如果还没有定义mainfuncH这个宏”,那么……</P>
      <P>那么之后做什么呢?就是一直到 #endif之间的语句。</P>
      <P> </P>
      <P>总的再来看一遍:</P>
      <P> </P>
      <P>mainfunc.h 中的主要内容:</P>
      <P> </P>
      <P>#ifndef mainfuncH</P>
      <P>#define mainfuncH</P>
      <P> </P>
      <P>void CalcTotal(int n);</P>
      <P>void CalcAverage(int n);</P>
      <P> </P>
      <P>#endif</P>
      <P> </P>
      <P>当编译第一次编译mainfunc.h文件时,宏 mainfuncH 还没有定义,因些,编译器通过对 #define 
      mainfuncH的编译而产生了宏 mainfuncH。当编译器第二次编译到 mainfunc.h文件时,宏mainfuncH 
      已经存在,所以该头文件被直接跳过,不会重复处理该头文件中内容,比如上面的两个函数声明。</P>
      <P>你可能会问两个问题:第一,为什么编译器可能多次编译到同一个头文件?第二,为什么源文件,比如mainfunc.cpp就不需要用到#ifndef... 
      #endif?</P>
      <P>这两个问题只要回答了其中一个,另一个也就自然消解。</P>
      <P> </P>
      <P>这是由头文件特性所决定的。头文件是用来被别人包含(include)的。谁都可以指定要包含某一头文件,这样就可能造成对该头文件的重复包含。</P>
      <P>假设有头文件head.h。如果A文件包含了head.h,而B文件也包含了head.h,那么编译器不会在编译A和编译B时,都要对该头文件尝试编译一次。</P>
      <P>另外,头文件本身也可以包含另一个头文件,这种情况下,各文件之间互相嵌套包含的情况就更多了。</P>
      <P> </P>
      <P>源文件(.c或.cpp)尽管可以,但一般不被用来被别的文件包含,所以不需要在源文件中加这些语句。当然,如果需要,你也可以源文件中使用 
      #ifndef...#endif。</P>
      <P> </P>
      <P>每生成一个头文件,包括在重命名它时,CB会为我们取好该头文件中,上述的宏名称,它取该头文件的全小写文件名,加上一个大写的‘H’字母,比如: 
      "mainfuncH"。请大家不要改变该宏的名称,以免出错。</P>
      <P> </P>
      <P>除了 #ifndef ... #endif 语句外,还有它的相反逻辑的语句:<SPAN lang=en>&nbsp;</SPAN> </P>
      <P>#ifdef ... #endif 它是在如果<B>有定义</B>某个宏,那么,编译将继续其后的语句。</P>
      <P> </P>
      <P>另外就像有if 语句,还有 if...else...语句一样,有 #ifdef ... #endif,也就还有这个语句:</P>
      <P>#ifdef </P>
      <P>... ...</P>
      <P>#else</P>
      <P>... ...</P>
      <P>#endif</P>
      <P> </P>
      <P>不过这些都和我们这里的头文件相关不大,我们暂时不讲。最后我们来解释一个名词“预编译”。</P>
      <P>编译器在编译代码时,至少需要两遍的编译处理,其中第一次,就是专门用于处理所有以 
      #开头的语句,如上述的#ifndef...#endif、#define等等。这一遍处理,我们称为<B>预编译</B>。</P>
      <P> </P>
      <H3><A name=14.4>14.4</A> 如何使用头文件</H3>
      <P> </P>
      <P>事实上我们经常在使用头文件。不过,以前我们一直在使用别人的头文件,今天是第一次使用我们自已的写的头件。</P>
      <P>以前,我们几乎每个例子,包括今天的例子中,都需要在源文件的顶部写上一行:</P>
      <P>#include &lt;iostream.h&gt;</P>
      <P>或者:</P>
      <P>#include &lt;stdio.h&gt;</P>
      <P> </P>
      <P>iostream.h和stdio.h都是CB提供给我们的头文件。这些头文件随CB安装时,被<B>保存在固定的文件夹内</B>。</P>
      <P>今天的例子中,main.cpp 需要使用到在 mainfunc.h 和 
      assifunc.h。这是我们自己写的头文件,它们<B>保存在我们自定的文件夹中</B>。</P>
      <P>包含自已写的头文件,和包含CB提供的头文件并无多大区别。</P>
      <P>请在 main.cpp 代码顶部,加入以下黑体部分:</P>
      <P> </P>
      <P>#include &lt;iostream.h&gt; </P>
      <P><B>#include "mainfunc.h" </B></P>
      <P><B>#include "assifunc.h" </B></P>
      <P>//--------------------------------------------------------------------------- 
      </P>
      <P> </P>
      <P>二者的细小区别是,包含CB提供的头文件时,用尖括号&lt;&gt;;而包含我们自已的头文件时,使用双引号“”。CB据此判断如何找到指定的头文件。&lt;&gt;相当于告诉CB,这是你自已提供的头文件,到你安装时的头文件目录下找去吧,而“”则是告诉CB,是这我自已写的头文件,请首先到我当前工程所在目录下查找,如果找不到,再到别的可能的头文件目录下找这个文件。(别的还有什么目录可能存放当前工程的头文件呢?稍后会讲。)</P>
      <P> </P>
      <P>现在,我们让main.cpp包含了它想要的头文件,头文件内有它所需函数的正确声明,那么main.cpp中原来的这三行就多余了:</P>
      <P><STRIKE>void CalcTotal(int n);</STRIKE></P>
      <P><STRIKE>void CalcAverage(int n);</STRIKE></P>
      <P><STRIKE>char ToUpper(char c);</STRIKE></P>
      <P>请删除。 然后,按F9,程序正确编译,然后运行。这里我们不关心它的运行结果。</P>
      <P> </P>
      <P>现在来看一眼在CB中如何设定某一工程的头文件目录。</P>
      <P>必须先说清楚,在相当长的一段时间内,我们并不需要去进行此设置。对于CB提供的头文件,它们固定就在CB安装时自动存储的某些目录下,你只要记得包含这些头文件时,使用&lt;&gt;即可。对于我们自已写的头文件,我们都把它们和工程文件存放在同一目录下,暂时还没有什么理由需要把某个或某些头文件“扔”在别的目录下。所以,记住在包含自己的头文件时,对使用“”即可。</P>
      <P>首先保证当前CB正打开着上面的那个例子工程。</P>
      <P>然后,主菜单: Project | Options 或按 Ctrl + Shift + F11,打开“工程设置(Project 
      Options)”对话框,并切换到“目录与条件(Directories/Conditionals)”页:</P>
      <P><IMG src="第14章 程序的文件结构.files/ls14.h2.jpg" border=0></P>
      <P> </P>
      <P>图中有关目录的设置共六行,我们说其中常用的四行。</P>
      <P>最主要的,当然是今天所说的“头文件目录”。当 CB 编译时,当它遇到这样一行:</P>
      <P> </P>
      <P>#include "xxxx.h"</P>
      <P>那么,它必须找到文件xxxx.h。如果,你写的是绝对路径:#include 
      "c:\abc\123\xxxx.h",那自然没有查找这一说,不过我们不会喜欢这样写程序,因为我们不希望源代换个位置就得一一去改那些绝对路径。事实上我们不可能把头文件到处放,总是固定那么几个目录,绝大多数就一个:所有源文件和头文件都在当前工程所在目录下。这里可以添加,删除,修改一些目录位置,CB将按本设置中的目录次序去查找头文件。</P>
      <P>请点击“头文件目录”右边,带 "..."的小按钮。出来一个新的对话框:</P>
      <P><IMG src="第14章 程序的文件结构.files/ls14.h4.jpg" border=0></P>
      <P><FONT color=#808080>($BCB) 表示Borland C++Builder 的安装目录。</FONT></P>
      <P> </P>
      <P>在这里,你可以修改(Replace),增加(Add),删除(Delete),调整次序(向上和向下的蓝箭头)各个头文件目录。CB6还提供了对无效目录的判断,如果列表中列出的某个目录实际上并不存在对应的文件夹,则将以灰色显示,并且可以用"Delete 
      Invalid Paths"按钮全部删除。</P>
      <P> </P>
      <P>我们什么也不用做。点 Cancel, 放弃就是。</P>
      <P> </P>
      <P>其它目录的设定,操作完全一样。</P>
      <P> </P>
      <P>关于在工程中如何使用头文件,我们就说这些了。</P>
      <P> </P>
      <H3><A name=14.5>14.5</A> 变量在多个源文件之间的使用</H3>
      <P>前面讲的是,通过在头文件中声明函数,可以达到让这个函数被其它文件共用的作用。同样地,变量也可以在多个源文件之间“共享”。下面我们就要讲,如何通过<B>声明变量</B>,以达到让其它文件共用同一个变量的目的。</P>
      <P> </P>
      <H4><A name=14.5.1>14.5.1</A> 变量声明</H4>
      <P>先说说“声明变量”。好像以前的课程只教过我们:定义变量,定义函数,声明函数,没有讲过“声明变量”啊?</P>
      <P> </P>
      <P>我们很早就学过如何定义一个变量。(<A 
      href="http://www.d2school.com/bcyl/bhcpp/newls/ls05.htm#5.1.2">5.1.2</A>) 
      </P>
      <P> </P>
      <P>比如:</P>
      <P> </P>
      <P>//定义一个整型变量:</P>
      <P>int age;</P>
      <P> </P>
      <P>//然后,在后面的某处代码中使用这个变量:</P>
      <P>... ...</P>
      <P>age = 18;</P>
      <P>cout &lt;&lt; age &lt;&lt; endl;</P>
      <P>... ...</P>
      <P> </P>
      <P> </P>
      <P>但是,我们没有遇到过如何声明一个变量。这是因为,定义一个变量的同时,也就声明了一个变量;绝大多数的时候,我们都是可以需要某个变量时,直接定义它。</P>

⌨️ 快捷键说明

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