久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4104|回復(fù): 2
打印 上一主題 下一主題
收起左側(cè)

C 、C++文件結(jié)構(gòu)關(guān)系(.C和.h)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:76127 發(fā)表于 2015-4-4 18:48 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
規(guī)范:所有的LCD.c中的子函數(shù)在LCD.h中聲明,哪個xx.C或 xx.h文件要用到子函數(shù),只需#include"LCD.h".LCD.h 是子函數(shù)的名片 申明和注釋
#ifndef LCD_H    //名字類似就行,它只是個符號,相當(dāng)于函數(shù)已申明標(biāo)志
#define LCD_H   //宏定義的另一種用法 :僅僅給出名稱 但是沒有值,就是在通過 編譯定義個符號 。緊接著就是聲明,直到 #endef;
void write_data();//注釋
void write_adr();//
#endef
# 開頭的叫  預(yù)處理 當(dāng)編譯第一次編譯LCD.h文件時,宏 LCD_H 還沒有定義,因些,編譯器通過對 #define LCD_H的編譯而產(chǎn)生了宏 LCD_H。當(dāng)編譯器第二次編譯到 LCD.h文件時,宏LCD_H 已經(jīng)存在,所以該頭文件被直接跳過,不會重復(fù)處理該頭文件中內(nèi)容,比如上面的兩個函數(shù)聲明。這就避免多個文件包含LCD.h時重復(fù)申明或其他的操作。   xx.C 文件中#include“LCD.C” 有時候編譯時出錯,或許就是因為其他XX.C文件也包含了LCD.C導(dǎo)致重復(fù)聲明和定義。14.1 源文件和頭文件 和別的一些語言不同,C,C++的代碼文件有“頭文件”和“代碼文件”之分。二者合起來我們稱為單元(Unit)文件。
擴展名為 .c 或 .cpp 的文件,主要用以實現(xiàn)程序的各種功能,我們稱為代碼文件。
擴展名為 .h 的文件,稱為頭文件。在頭文件里主要寫一些函數(shù)、數(shù)據(jù)(包括數(shù)據(jù)類型的定義)、等的聲明,這樣可以在多個.c或.cpp文件內(nèi)共享這些函數(shù)、數(shù)據(jù)。第12章我們提過到頭文件的功能。說它可以起到函數(shù)“名片夾”的作用。
大都數(shù)時候,源文件和頭文件是對應(yīng)出現(xiàn)的,比如有一個 A.cpp 的源文件,就會有一個 A.h 的頭文件。這種情況在我們寫應(yīng)用程序時,更是常見。所以C++ Builder對此進行了強化。比如,它支持在同名源文件和頭文件之間通過熱鍵來回切換。在CB6.0里,編輯器打開對應(yīng)的源文件和頭文件時,將顯示為同一頁下的兩個子頁。 
我們來實際動手看看源文件與頭文件在CB里的對應(yīng)關(guān)系。
運行 C++ Builder 6或5。
這一次我們需要一個空白的Windows工程。很有可能,在你打開CB時,它就自動為你打開了一個工程。為了不出錯,我們還是親自建一個。CB6請使用主菜單:File | New | Application;而CB5則使用:File | New Application 新建一個Windows 空白工程。 如果在這過程中CB出現(xiàn)是否存盤的詢問,請回答不存盤。
找到“代碼窗口”。如果你看到的是一個叫"Form1"的表單,請按F12,“代碼窗口”將跑到前面。它的標(biāo)題應(yīng)該是默認(rèn)的"Unit1.cpp"。正是當(dāng)前代碼文件的文件名。如下圖:



對于CB6,還可以看到在該窗口的底部有這樣一個分頁:


文件:Unit1.cpp 和頭文件:Unit1.h 并列著,我們可以方便地選擇。至于 "Diagram",稱為“圖解”。這是一個給這個源文件加配套注解,及表單上各控件的依賴關(guān)系的地方。如果是一個開發(fā)小組在進行共同開發(fā),嚴(yán)格地要求每個成員為每個單元文件寫上“Diagram”,可以更好地實現(xiàn)程序員之間的溝通。
CB5沒有這些,不過下面的熱鍵操作兩個版本均一樣的,要求大家記住。
按 Ctrl + F6 可以在源文件和頭文件之間來回切換。請大家試試。這個簡單的操作將在我們今后的編程過程中高頻率地使用。

14.2 如何創(chuàng)建多個單元文件
前面我們在“Windows應(yīng)用程序工程”中看到了頭文件與源文件的匹配關(guān)系,在“控制臺”的工程中,也同樣存在。不過由于控制臺經(jīng)常只用來寫一些小小的程序,所以往往只需一個源文件即可。由于只有一個源文件,所以也就不存在函數(shù)、數(shù)據(jù)在多個文件之間“共享”的需要,因此邊頭文件也就可以不提供。

那么,是不是只有在程序很大,或者只有在有很多人同時開發(fā)一個軟件時,才需要多個源文件呢?
這就好像你家里只有兩本書:《紅樓夢》和《格林童話》,是把它們放在同一個抽屜里呢?還是分開放到兩個抽屜里?我覺得后者是比較好的選擇。因為我們常常希望家里看《格林童話》的人,最好不要去看《紅樓夢》。
程序也一樣,最好把不同的邏輯實現(xiàn),放到不同的源文件中。

下面我們做一個實例。例子的代碼我們都已經(jīng)學(xué)過。目標(biāo)是實現(xiàn)一個可以求統(tǒng)計值和平均值的程序。
根據(jù)我們現(xiàn)在所學(xué)的情況,我把這個工程中的代碼分為三個源代碼:
其一:主程序。就是main()函數(shù)所在的代碼。這個源文件實現(xiàn)總的流程。我將該文件取為 main.cpp。
其二:計算總和及計算平均值的代碼。這個源文件負(fù)責(zé)用戶計算過程,也包括每個過程所需輸入輸出。該文件將被存盤為mainfunc.cpp。 意為主要功能。
其三: assifunc.cpp。表示輔助功能函數(shù)所在代碼。它只提供一個函數(shù):將用戶輸入的大寫或小寫的字母'Y'或'N' 確保轉(zhuǎn)換為大寫。這個函數(shù)將main()主函數(shù)內(nèi),判斷用戶是否繼續(xù)時用到。

新CB新建一個控制臺程序(如果你還開著上個程序,先選File | Close All關(guān)閉它)。CB會自動生成第一個文件,不過現(xiàn)在的名字為“Unit1.cpp"。
接下來是一項新工作,我們來添加兩人新的單元文件,即上面說的“其二”和“其三”。
CB6 :File | New | Unit;CB5:File | New Unit。
請進行兩次以上操作,CB將為我們生成新的兩個單元文件:Unit2.cpp和Unit3.cpp。大家可以再試試 Ctrl + F6。(注意,第一個單元文件:Unit1.cpp 沒有配套的.h文件,所以不要在該文件里嘗試Ctrl + F6)。
然后選擇File | Save All。全部存盤,最好不要存在CB默認(rèn)的目錄下。記得按以下關(guān)系重命名:
Unit1.cpp 存盤為 main.cpp;
Unit2.cpp 存盤為 mainfunc.cpp;
Unit3.cpp 存盤為 assifunc.cpp;
至于總的工程,隨你便,我圖方便,還是叫:Project1.bpr。

(現(xiàn)在我們第一次在一個工程中用到多個源文件。所以你得學(xué)會如何快速打開一個工程中某個源文件——當(dāng)然,現(xiàn)在這三個文件都已經(jīng)打開著,不過假設(shè)你有點事關(guān)閉CB,我們不希望下回打開這個工程時,你“找”不到第2和第3個文件了——請點擊CB工具欄上的這個圖標(biāo):,將出現(xiàn)源文件列表對話框,如左圖)


接下來講在這三個文件中,我們分別寫些什么?大多數(shù)代碼我們都已經(jīng)在前面學(xué)過,所以我對代碼的功能不作太多的解釋。我們的重點是:三個源文件之間的代碼如何實現(xiàn)“溝通”。

第一個文件:main.cpp 用來實現(xiàn)程序的主流程。
在 main.cpp 中的main()函數(shù)內(nèi),我們加入代碼。

#include <iostream.h>
... ...
int main(int argc, char* argv[])
{
   char ch;
   int count; //求總和或平均值時,需要輸入的成績個數(shù)


   do
   {
      cout << "1)求總和" << endl;
      cout << "2)求平均" << endl;

      cout << "請選擇(1 或 2)";
      cin >> ch;

      //輸入有誤,重輸:
      if(ch != '1' && ch != '2')
      {
         cout << "輸入有誤,請重新輸入!" << endl;
         continue;
      }

      cout << "請輸入個數(shù):";
      cin >> count;

      //根據(jù)用戶的選擇,調(diào)用不同函數(shù):
      switch(ch)
      {
         case '1' :
            CalcTotal(count); //需要調(diào)用的函數(shù)之一
            break;
         case '2' :
            CalcAverage(count); //需要調(diào)用的函數(shù)之一
            break;
      }

      //是否繼續(xù):
      cout << "是否繼續(xù)?(y/n)";
      cin >> ch;

      //確保轉(zhuǎn)換為大寫:
      ch = ToUpper(ch); //需要調(diào)用的函數(shù)之一
   }
   while(ch == 'Y');

   return 0;
}

代碼中,紅色部分的注釋表明,主函數(shù)main()需要調(diào)用到三個自定義函數(shù)。但現(xiàn)在我們一個也沒有定義。和往常把所有的函數(shù)定義在同一個代碼文件中不同,今天我們需要把它們分開到不同的代碼文件。

第二個文件:mainfunc.cpp 存放和計算有關(guān)的兩個過程(函數(shù))。
先看:CalcTotal()和CalcAverage()。這兩個函數(shù)我們將在mainfunc.cpp文件內(nèi)定義。你可能又忘了“定義”這個術(shù)語?呵,就是“實現(xiàn)”,更白點,就是在mainfunc.cpp文件內(nèi)“寫”這兩個函數(shù)。

下面是mainfunc.cpp的內(nèi)容。在我們輸入以下代碼時,mainfunc.cpp已經(jīng)有了一些必要的內(nèi)容,下面的代碼,除了“#include ..”一行在文件最首外,其它均在原有內(nèi)容之后添加。

#include <iostream.h> //在文件最首行
... ...
//---------------------------------------------------------------------------
//求總和的過程
//參數(shù):n 用戶需要輸入的個數(shù)
void CalcTotal(int n)
{
   int num;
   int sum = 0;

   for(int i=0;i<n;i++)
   {
      cout << "請輸入第" << i+1 <<"個整數(shù):";
      cin >> num;

      sum += num;
   }

   cout << "總和為:" << sum << endl;
}
//---------------------------------------------------------------------------
//求平均值的過程
//參數(shù):n 用戶需要輸入的個數(shù)
void CalcAverage(int n)
{
   int num;
   int sum = 0;
   float ave;

   for(int i=0;i<n;i++)
   {
      cout << "請輸入第" << i+1 <<"個整數(shù):";
      cin >> num;

      sum += num;
   }

   //注意不要除0出錯:
   if( n >=0 )
   {
      ave = (float)sum / n;
      cout << "平均值:" << ave << endl;
   }
   else
   {
      cout << "個數(shù)為0,不能求平均。" << endl;
   }
}
//---------------------------------------------------------------------------

第三個文件:assifunc.cpp 用以存放輔助作用的函數(shù),現(xiàn)在只有一個。
現(xiàn)在還差一個函數(shù):ToUpper()。這個函數(shù)用來將用戶輸入的某個小寫字母轉(zhuǎn)換為大寫。當(dāng)然,如果用戶輸入的不是小寫字母,那就不用轉(zhuǎn)換。和上面的兩個函數(shù)不同,它需要返回值。
我們把ToUpper()函數(shù)單獨放在assifunc.cpp里。同樣,下面的代碼加在該文件中原有的代碼之后。不過本文件不需要include <iostream.h> ,因為沒有用到 cin,cout等。

//小寫字母轉(zhuǎn)換為大寫
//參數(shù): c 待轉(zhuǎn)換的字符
//返回值: 轉(zhuǎn)換后的字符,如果原字符不是小寫字母,則為原字符
char ToUpper(char c)
{
   int ca = 'A' - 'a'; //大寫字母和小寫字母之間差距多少?


   if(c >= 'a' && c <= 'z')
      c += ca;
 
   return c;
}

至此,所有自定義函數(shù)都已完成定義(實現(xiàn)),而三個文件的主要內(nèi)容也以確定。讓我們看看示意圖:



main.cpp中的main()函數(shù)調(diào)用了三個函數(shù)。回憶我們學(xué)習(xí)過的“如何調(diào)用函數(shù)”的知識,當(dāng)前代碼在調(diào)用一個函數(shù)時,必須能“看到”這個函數(shù)。盡管CalcTotal()、CalcAverage()、ToUpper()三個函數(shù)所在文件都在同一工程里,但是在main.cpp里的代碼,還是看不到它們。想一想我們以前說的“請修理工”的比喻。現(xiàn)在情況是:在你所住的小區(qū),甚至就是同一樓道里,就有一個電視修理工,但可惜你們互不認(rèn)識,所以當(dāng)你電視壞了,想“調(diào)用”一個修理工時,你還是找不到修理工。哎!要是有它的名片就好了。
讓我們試試看,按Ctrl + F9,編輯該工程。出錯!

正好是三個錯。分別告訴我們調(diào)用了三個沒有定義的函數(shù)(Call to undefined function ...)。

(如果你出現(xiàn)的是一堆錯,那有可能是你沒有在前兩個文件內(nèi)最首行寫:
“#include <iostream.h>”
或者是你有些代碼輸入有誤。)

如何消除這三個錯?兩種方法。
第一種方法就是以前我們在講“如何調(diào)用函數(shù)”的時候所說的,直接在調(diào)用直接聲明要調(diào)用的函數(shù)。這里寫出代碼,算做是一次復(fù)習(xí),然后我們將講該方法不好之處。

在 main.cpp 的 main()函數(shù)之前加入如下三行函數(shù)聲明:

void CalcTotal(int n);
void CalcAverage(int n);
char ToUpper(char c);

int main(int argc, char* argv[])
{
   ... ...
}

(上例中,盡管你可以將三行函數(shù)聲明寫在 main()函數(shù)體內(nèi),但不建議這樣做)。

如果你一切輸入正確的話,現(xiàn)在按Ctrl + F9 或 F9將可以完成編譯或運行。
對于現(xiàn)在這個工程,這種方法確實也不能指責(zé)它有何不利之處。問題在于,如果我們還有其它文件中代碼需要調(diào)用到這三個函數(shù),我們就不得不在其它文件中也一一寫上這三行聲明。所以另一種方法是:把源文件中需要對外“共享”的函數(shù)聲明統(tǒng)一寫到某個頭文件,然后凡是需要用到的其它文件,直接使用“#include"語句來包含該頭文件,從而獲得這些函數(shù)聲明。

14.3 如何寫頭文件
在CB中,如果你通過上小節(jié)的方法新建個單元文件,那么CB將自動同時生成源文件和頭文件。其實在CB里,源文件和頭文件合稱為單元文件,它們有相同的文件名,而擴展名一者為.cpp,另一為.h。

14.3.1 在頭文件內(nèi)加入函數(shù)聲明
頭文件:mainfunc.h
CalcTotal()和CalcAverage()函數(shù)定義在 mainfunc.cpp文件里,所以它們的聲明最好寫在對應(yīng)的頭文件mainfunc.h內(nèi)。
下面我們就來看如何在頭文件mainfunc.h 內(nèi)增加函數(shù)聲明。
一開始,頭文件內(nèi)有以下這些代碼。另外,我增加了一行用于標(biāo)明我們新加的代碼應(yīng)寫在哪里。
//---------------------------------------------------------------------------


#ifndef mainfuncH
#define mainfuncH
//---------------------------------------------------------------------------
/* !!!頭文件中,我們新增的代碼必須寫在此處!!!  */
#endif

和源文件中新增代碼添加在最后不一樣,頭文件中新加代碼 必須在#endif之前插入。所以本例中,加完函數(shù)聲明的代碼應(yīng)如其下所示。(另外,CB總是在頭文件的第二行留了一行空白行,我不知道它這是有意還是無意。總之這里是我們寫本文件總體注釋的好地方。記住,頭文件像名片,用于讓別人看,很有必要寫得詳細(xì)點)
//---------------------------------------------------------------------------
   //主要操作函數(shù)
#ifndef mainfuncH
#define mainfuncH
//---------------------------------------------------------------------------
//計算總和:
void CalcTotal(int n);
//計算平均值:
void CalcAverage(int n);
//---------------------------------------------------------------------------
#endif

這就是“在頭文件中聲明函數(shù)”的整個過程。下面是另外一個頭文件。

頭文件:mainfunc.h
//---------------------------------------------------------------------------
//輔助操作函數(shù)
#ifndef assifuncH
#define assifuncH
//---------------------------------------------------------------------------
//將字符轉(zhuǎn)換成大寫
char ToUpper(char c);
#endif

今天我們學(xué)的是如何在頭文件內(nèi)聲明函數(shù),以后我們需要在頭文件內(nèi)聲明變量,或者定義新的數(shù)據(jù)類型,它們都一樣需要在上述的#endif之前加入。

14.3.2 最常見的預(yù)編譯語句
現(xiàn)在來解釋這三行話:
#ifndef mainfuncH
#define mainfuncH

#endif

中間的 #define mainfuncH 我們有點臉熟。在第五章《變量與常量》中,我們講過用宏表示常數(shù)。語法為:
#define 宏名稱 宏值

比如,定義一個∏值:
#define PAI 3.14159

這里我們學(xué)的是宏定義的另一種用法:僅僅定義一個宏,不需要給出它的值,語法為:

#define 宏名稱

比如:#define mainfuncH

定義了一個宏:mainfuncH。如果你無法理解“宏”這個詞,不妨就當(dāng)把它解釋成“記號”。即編譯器通過該語句,做了一個記號,記號名稱為:mainfucH。
這么做的作用是什么呢?我們繼續(xù)看上下文。

#ifndef 中, if 是“如果”,n 是 no,即“還沒有”,def是 define,即“定義”,那么:
#ifndef mainfuncH 意為:“如果還沒有定義mainfuncH這個宏”,那么……
那么之后做什么呢?就是一直到 #endif之間的語句。

總的再來看一遍:

mainfunc.h 中的主要內(nèi)容:

#ifndef mainfuncH
#define mainfuncH

void CalcTotal(int n);
void CalcAverage(int n);

#endif

當(dāng)編譯第一次編譯mainfunc.h文件時,宏 mainfuncH 還沒有定義,因些,編譯器通過對 #define mainfuncH的編譯而產(chǎn)生了宏 mainfuncH。當(dāng)編譯器第二次編譯到 mainfunc.h文件時,宏mainfuncH 已經(jīng)存在,所以該頭文件被直接跳過,不會重復(fù)處理該頭文件中內(nèi)容,比如上面的兩個函數(shù)聲明。
你可能會問兩個問題:第一,為什么編譯器可能多次編譯到同一個頭文件?第二,為什么源文件,比如mainfunc.cpp就不需要用到#ifndef... #endif?
這兩個問題只要回答了其中一個,另一個也就自然消解。

這是由頭文件特性所決定的。頭文件是用來被別人包含(include)的。誰都可以指定要包含某一頭文件,這樣就可能造成對該頭文件的重復(fù)包含。
假設(shè)有頭文件head.h。如果A文件包含了head.h,而B文件也包含了head.h,那么編譯器不會在編譯A和編譯B時,都要對該頭文件嘗試編譯一次。
另外,頭文件本身也可以包含另一個頭文件,這種情況下,各文件之間互相嵌套包含的情況就更多了。

源文件(.c或.cpp)盡管可以,但一般不被用來被別的文件包含,所以不需要在源文件中加這些語句。當(dāng)然,如果需要,你也可以源文件中使用 #ifndef...#endif。

每生成一個頭文件,包括在重命名它時,CB會為我們?nèi)『迷擃^文件中,上述的宏名稱,它取該頭文件的全小寫文件名,加上一個大寫的‘H’字母,比如: "mainfuncH"。請大家不要改變該宏的名稱,以免出錯。

除了 #ifndef ... #endif 語句外,還有它的相反邏輯的語句:  
#ifdef ... #endif 它是在如果有定義某個宏,那么,編譯將繼續(xù)其后的語句。

另外就像有if 語句,還有 if...else...語句一樣,有 #ifdef ... #endif,也就還有這個語句:
#ifdef
... ...
#else
... ...
#endif

不過這些都和我們這里的頭文件相關(guān)不大,我們暫時不講。最后我們來解釋一個名詞“預(yù)編譯”。
編譯器在編譯代碼時,至少需要兩遍的編譯處理,其中第一次,就是專門用于處理所有以 #開頭的語句,如上述的#ifndef...#endif、#define等等。這一遍處理,我們稱為預(yù)編譯

14.4 如何使用頭文件
事實上我們經(jīng)常在使用頭文件。不過,以前我們一直在使用別人的頭文件,今天是第一次使用我們自已的寫的頭件。
以前,我們幾乎每個例子,包括今天的例子中,都需要在源文件的頂部寫上一行:
#include <iostream.h>
或者:
#include <stdio.h>

iostream.h和stdio.h都是CB提供給我們的頭文件。這些頭文件隨CB安裝時,被保存在固定的文件夾內(nèi)
今天的例子中,main.cpp 需要使用到在 mainfunc.h 和 assifunc.h。這是我們自己寫的頭文件,它們保存在我們自定的文件夾中
包含自已寫的頭文件,和包含CB提供的頭文件并無多大區(qū)別。
請在 main.cpp 代碼頂部,加入以下黑體部分:

#include <iostream.h>
#include "mainfunc.h"
#include "assifunc.h"
//---------------------------------------------------------------------------

二者的細(xì)小區(qū)別是,包含CB提供的頭文件時,用尖括號<>;而包含我們自已的頭文件時,使用雙引號“”。CB據(jù)此判斷如何找到指定的頭文件。<>相當(dāng)于告訴CB,這是你自已提供的頭文件,到你安裝時的頭文件目錄下找去吧,而“”則是告訴CB,是這我自已寫的頭文件,請首先到我當(dāng)前工程所在目錄下查找,如果找不到,再到別的可能的頭文件目錄下找這個文件。(別的還有什么目錄可能存放當(dāng)前工程的頭文件呢?稍后會講。)

現(xiàn)在,我們讓main.cpp包含了它想要的頭文件,頭文件內(nèi)有它所需函數(shù)的正確聲明,那么main.cpp中原來的這三行就多余了:
void CalcTotal(int n);
void CalcAverage(int n);
char ToUpper(char c);
請刪除。 然后,按F9,程序正確編譯,然后運行。這里我們不關(guān)心它的運行結(jié)果。

現(xiàn)在來看一眼在CB中如何設(shè)定某一工程的頭文件目錄。
必須先說清楚,在相當(dāng)長的一段時間內(nèi),我們并不需要去進行此設(shè)置。對于CB提供的頭文件,它們固定就在CB安裝時自動存儲的某些目錄下,你只要記得包含這些頭文件時,使用<>即可。對于我們自已寫的頭文件,我們都把它們和工程文件存放在同一目錄下,暫時還沒有什么理由需要把某個或某些頭文件“扔”在別的目錄下。所以,記住在包含自己的頭文件時,對使用“”即可。
首先保證當(dāng)前CB正打開著上面的那個例子工程。
然后,主菜單: Project | Options 或按 Ctrl + Shift + F11,打開“工程設(shè)置(Project Options)”對話框,并切換到“目錄與條件(Directories/Conditionals)”頁:


圖中有關(guān)目錄的設(shè)置共六行,我們說其中常用的四行。
最主要的,當(dāng)然是今天所說的“頭文件目錄”。當(dāng) CB 編譯時,當(dāng)它遇到這樣一行:

#include "xxxx.h"
那么,它必須找到文件xxxx.h。如果,你寫的是絕對路徑:#include "c:\abc\123\xxxx.h",那自然沒有查找這一說,不過我們不會喜歡這樣寫程序,因為我們不希望源代換個位置就得一一去改那些絕對路徑。事實上我們不可能把頭文件到處放,總是固定那么幾個目錄,絕大多數(shù)就一個:所有源文件和頭文件都在當(dāng)前工程所在目錄下。這里可以添加,刪除,修改一些目錄位置,CB將按本設(shè)置中的目錄次序去查找頭文件。
請點擊“頭文件目錄”右邊,帶 "..."的小按鈕。出來一個新的對話框:

($BCB) 表示Borland C++Builder 的安裝目錄。

在這里,你可以修改(Replace),增加(Add),刪除(Delete),調(diào)整次序(向上和向下的藍箭頭)各個頭文件目錄。CB6還提供了對無效目錄的判斷,如果列表中列出的某個目錄實際上并不存在對應(yīng)的文件夾,則將以灰色顯示,并且可以用"Delete Invalid Paths"按鈕全部刪除。

我們什么也不用做。點 Cancel, 放棄就是。

其它目錄的設(shè)定,操作完全一樣。

關(guān)于在工程中如何使用頭文件,我們就說這些了。

14.5 變量在多個源文件之間的使用前面講的是,通過在頭文件中聲明函數(shù),可以達到讓這個函數(shù)被其它文件共用的作用。同樣地,變量也可以在多個源文件之間“共享”。下面我們就要講,如何通過聲明變量,以達到讓其它文件共用同一個變量的目的。

14.5.1 變量聲明先說說“聲明變量”。好像以前的課程只教過我們:定義變量,定義函數(shù),聲明函數(shù),沒有講過“聲明變量”啊?

我們很早就學(xué)過如何定義一個變量。(5.1.2)

比如:

//定義一個整型變量:
int age;

//然后,在后面的某處代碼中使用這個變量:
... ...
age = 18;
cout << age << endl;
... ...


但是,我們沒有遇到過如何聲明一個變量。這是因為,定義一個變量的同時,也就聲明了一個變量;絕大多數(shù)的時候,我們都是可以需要某個變量時,直接定義它。

今天的情況有點不一樣。我們需要在某個源文件中定義一個變量,然后,在另外一個源文件中使用這個變量。

仍以前面 age 變量為例:

//我們在 A.cpp 文件中定義了這個變量:
int age;

//然后,在 B.cpp 文件中要使用這個變量:
age = 18;
cout << age << endl;

問題就出來了:在編譯 B.cpp 文件時,編譯器會說:“age 這個變量沒有定義啊?”——當(dāng)編譯器在編譯 B.cpp時,它并不懂得去A.cpp里去找有關(guān) age 的定義。
那么,能不能在B.cpp里再定義一次age變量呢?

//A.cpp文件中:
int age;

//B.cpp文件中:
int age;
age = 18;
cout << age << endl;

這樣,單獨編譯A.cpp,或B.cpp,都可以通過。但一旦要編譯整個工程,編譯器又會報錯:“怎么有兩個 age 變量的定義啊”?
不要嘲笑編譯器為什么這么笨笨。C,C++是一門嚴(yán)謹(jǐn)?shù)牡挠嬎銠C語言,我們不能指望編譯器會“智能”地猜測程序員的企圖。

解決方法是,僅在一處定義變量,別的代碼需要用到該變量,但無法看到前面的定義時,則改為“聲明變量”。

聲明變量的語法:
extern 數(shù)據(jù)類型 變量名

和定義變量的語法相比,多了前面的 extern 這個關(guān)鍵字。

extern 意為“外來的”···它的作用在于告訴編譯器:有這個變量,它可能不存在當(dāng)前的文件中,但它肯定要存在于工程中的某一個源文件中。

這就好像:微軟公司在北京招人,微軟的報名方法是:在北京的應(yīng)聘者必須當(dāng)天去面試,而外地應(yīng)聘者則通過發(fā)e-mail先報名,然后以后再去面試。 在C,C++里,不處于當(dāng)前源文件中的變量被稱為外部變量。比喻中,發(fā)e-mail就相當(dāng)于外部變量在某一個源中寫個聲明。聲明什么呢?就是聲明“我存在啊!雖然我現(xiàn)在不在這里,但是我真的存在!”

上例中,正確的代碼應(yīng)該這樣寫:

//A.cpp文件中:
int age;

//B.cpp文件中:
extern int age;
age = 18;
cout << age << endl;

變量 age 是在A.cpp文件里定義的,當(dāng)B.cpp文件要使用它時,必須先聲明。這就是我們講半天課的核心。

(有些教材并不認(rèn)為 extern int age; 是在聲明一個變量,它們把這也稱為是“定義變量”的一種,只不過它是定義了一個名部變量。我認(rèn)為這樣認(rèn)為不好,一來它造成了學(xué)習(xí)者認(rèn)為“變量可以重復(fù)定義”的錯誤認(rèn)為,二來它也造成了不統(tǒng)一,函數(shù)有“定義”和“聲明”兩種形式,而變量都沒有“聲明”。
可能你會說,現(xiàn)在也不統(tǒng)一啊?函數(shù)聲明沒有“extern",而變量卻需要?呵呵,其實恰恰相反。函數(shù)聲明本來也是需要一個“extern”的,比如:

extern void CalcTotal(int n);
你在代碼里這樣完全正確!只不過由于函數(shù)聲明和函數(shù)定義的格式區(qū)別很大,(聲明沒有函數(shù)體,定義則必須有函數(shù)體),所以這個extern就算不寫,也可以讓編譯器認(rèn)出來它是一個“聲明”。結(jié)果就規(guī)定可以不寫"extern"了。
而變量呢?
extern int age;     //這是聲明
int age;            //這是定義
你看看,不寫"extern"可不行! 就靠它來區(qū)分是定義還是聲明了。
如此而已。)

14.5.2 多個文件中共享變量的實例
做一個最簡單的例子。新建一個控制臺工程。然后再加一個單元文件。把工程存盤為Project1.bpr,把兩個源文件分別存盤為Unit1.cpp、Unit2.cpp (即,都采用默認(rèn)文件名)。

程序內(nèi)容是:在 Unit1.cpp 內(nèi)定義一個變量,即:int age,并且,要求用戶輸入。在Unit2.cpp里,寫一函數(shù),OutputAgeText(),它根據(jù) age 的值, 輸出一些文本。

請問,變量 age 在哪里定義?又在哪里聲明?

定義指定是在 Unit1.cpp 文件里,而聲明,則可以在 Unit2.cpp內(nèi)直接聲明(如上例中的紅色代碼),也可以是在頭文件 Unit1.h 里聲明,然后在 Unit2.cpp 內(nèi)使用 include 來包含 Unit1.h。 事實讓,聲明也可以放在 Unit2.h內(nèi)。只要能讓Unit2.cpp“看到”這個聲明即可。這一點和函數(shù)的聲明一個道理。

我們采用放在Unit2.cpp中的方法,該方法所需代碼如下:

//Unit1.cpp 內(nèi)的主要代碼:

#include <iostream.h>
#include <conio.h>
#pragma hdrstop
#include "Unit2.h"
... ...
//---------------------------------------------------------------------------
int age; //全局變量,年齡
#pragma argsused
int main(int argc, char* argv[])
{
  cout << "請輸入您的年齡:" ;
   cin >> age;

   //調(diào)用Unit2.cpp中的函數(shù),該函數(shù)根據(jù)age,作出相應(yīng)輸出
   OutAgeText();   

   getch();
   return 0;
}
//---------------------------------------------------------------------------


//Unit2.cpp 中的主要代碼:
#include <iostream.h>
... ...
extern int age;  //需要Unit1.cpp內(nèi)定義的變量

//報名參加“沒有彎路”的學(xué)員各行業(yè),年齡段也各處不同,在此,我們用這個函數(shù)作為共勉!
void OutAgeText()
{
   if(age < 15)
      cout  << "計算機要從娃娃抓起!" << endl;
   else if(age < 25)
      cout << "青春年華,正是學(xué)習(xí)編程的黃金時代!" << endl;
   else if(age < 35)
      cout << "學(xué)習(xí)編程需要熱情,更需要理性!我和您一樣,也在這個年齡段!"<< endl;
   else if(age < 45)
      cout << "活到老,學(xué)到老!何況您還未老。殺毒王王江民,不也在這個時候才開始學(xué)習(xí)電腦嗎?" << endl;
   else
      cout <<  "前輩,只要您像學(xué)書法一樣潛心學(xué)編程!您一定會有收獲!" << endl;
}
//---------------------------------------------------------------------------
 

//Unit2.h 的主要代碼:

//聲明OutAgeText()函數(shù),供Unit1.cpp使用
void OutAgeText();
//---------------------------------------------------------------------------
 
請大家完成這個工程,直到能正確運行。

現(xiàn)在我們得到一個印象:當(dāng)我們定義了一個函數(shù)或變量之后,似乎所有的源代碼文件中都可以使用它,只要你在使用之前寫一下相應(yīng)的聲明。
這樣會不會帶來麻煩了?想象一下,你在A文件定義了一個變量: int i, 那么以后你在別的文件里就不能再定義這個變量了!原因前面已經(jīng)說過,編譯器(或鏈接器)會說有兩個變量重名。函數(shù)也一樣,盡管它有重載機制,便那也只能是有限制地允許函數(shù)重名。

事實上,上例中的 int age 是一個全局變量。關(guān)于“全局”的解釋,需要引起C,C++程序的另一話題:作用范圍。這是下一章的內(nèi)容。在那一章里,我們將看到,大部分變量只在它一定的作用范圍內(nèi)“生存”,不同的作用范圍的變量就可以毫無障礙地重名了。
休息休息(該點眼藥水了···),然后學(xué)習(xí)本章附加一節(jié)。

14.6 附:如何單獨生成一個頭文件
在 14.5.2 試一試在多個文件中共享變量 小節(jié)中,我們說,變量的聲明可以像函數(shù)聲明一樣放在某個頭文件中,然后使用者通過 include語句包含該頭文件,從而獲得變量的聲明。

如果你想自已再寫一次那個例子(建議),并且改用上述的方法,那么你可能會發(fā)現(xiàn)一個小小的故障: Unit1.cpp竟然沒有配套的頭文件?

CB 在生成一個空白的控制臺工程時,會自動主函數(shù)(main())文件,即默認(rèn)文件名為:Unit1.cpp的源文件,但它沒有為該文件生成對應(yīng)Unit1.h。
這是因為作為控制臺程序,一般都是小程序,一個源文件即可全部解決。

現(xiàn)在,作為一個課程例子,我們要來講講如何為Unit1.cpp生成一個頭文件。

CB6中選擇菜單:New | Other,CB5中選擇 New...,或直接點“”,出現(xiàn)New Item...對話框,選擇 New頁內(nèi)的 Header File:


確認(rèn)后,CB生成頭文件: File1.h,其內(nèi)容為空白,我們需要手工加入以下內(nèi)容:

#ifndef unit1H
#define unit1H

#endif

然后,選擇主菜單 File | Save As... 將其另存為: Unit1.h。 完后成,在Unit1.cpp或Unit1.h內(nèi),按Ctrl + F6,你就可以看到二者之間的切換了。


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:74571 發(fā)表于 2015-4-10 10:26 | 只看該作者
還不錯
回復(fù)

使用道具 舉報

板凳
ID:85441 發(fā)表于 2015-7-12 10:48 | 只看該作者
我想試用C++builder編個上位機,但是為什么我添加串口調(diào)試器,總是不成功?c++builder6.0必須要在XP系統(tǒng)上才能試用嗎?   求教
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 天天操妹子| 九九伦理片 | 天天视频成人 | 日韩免费一区 | 一级黄色日本片 | 亚洲二区在线 | 国际精品鲁一鲁一区二区小说 | 久久av综合 | 亚洲一区二区久久久 | 午夜精品久久久久99蜜 | 国产欧美视频一区二区三区 | 国产乱码精品一区二三赶尸艳谈 | 天天影视亚洲综合网 | 午夜免费观看网站 | 亚洲国产中文在线 | 97精品久久| 国产午夜精品久久久 | 91国内精精品久久久久久婷婷 | 男女久久久| 野狼在线社区2017入口 | 欧美成人a∨高清免费观看 老司机午夜性大片 | 日韩欧美视频免费在线观看 | 国产精品爱久久久久久久 | 国产欧美精品一区二区 | 精品一区二区电影 | 色接久久| 成人av高清| 久久成人精品一区二区三区 | 天天拍天天插 | 噜噜噜色网 | 午夜日韩精品 | 亚洲精品一区av在线播放 | 热re99久久精品国产99热 | 欧美日韩国产在线观看 | 免费看淫片 | 欧美八区 | 国产精品久久久乱弄 | 国产小视频精品 | 国产日韩免费视频 | 国产精品一区二区无线 | 欧美a区 |