電腦遊戲製作開發設計論壇 首頁 電腦遊戲製作開發設計論壇
任何可以在PC上跑的遊戲都可以討論,主要以遊戲之製作開發為主軸,希望讓台灣的遊戲人有個討論、交流、教學、經驗傳承的園地
 
 常見問題常見問題   搜尋搜尋   會員列表會員列表   會員群組會員群組   會員註冊會員註冊 
 個人資料個人資料   登入檢查您的私人訊息登入檢查您的私人訊息   登入登入 

Google
[C++][11]標頭檔案(Header Files)

 
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 遊戲程式初級班:語法及基礎概念
上一篇主題 :: 下一篇主題  
發表人 內容
yag
Site Admin


註冊時間: 2007-05-02
文章: 688

2673.35 果凍幣

發表發表於: 2007-10-31, AM 12:09 星期三    文章主題: [C++][11]標頭檔案(Header Files) 引言回覆

好久沒有寫新的教學了,本來上星期日就打算新增這篇的,範例程式的部份已經用好了,但最近這幾天卻又都被某些事拖住了,結果一拖再拖,再這樣下去恐怕永遠沒有寫出來的一天,所以趁著今天睡前還有點時間,多多少少寫一些。

這次要講的是標頭檔案(Header Files),什麼是標頭檔?大家應該不陌生了,我們之前的範例從一開始就有用到#include <iostream>,這iostream就是標頭檔。

一般來說,標頭檔的副檔名是.h,或者.hpp(c++專用),不過微軟提供的很多標頭檔都是沒有副檔名的,像是我們常常引用的iostream,但這並不影響它的功能。

要引用標頭檔,當然就是使用#include指令,而正如之前某篇教學裡說過的,用角刮號< >把標頭檔名刮起來代表從系統預設的路徑開始找尋此檔案,用雙引號" "刮起來的,代表從目前方案檔所在資料夾開始找尋此檔案。

至於系統預設路徑,則如下圖所示,可以在打開Visual Studio 2005 pro後,於「工具」→「選項」→「專案和方案」→「VC++目錄」裡看到,平台選擇「Win32」,顯示目錄選擇「Include檔案」,便可看到目前設定的系統預設路徑:


#include是個前置處理器的指令,它的功能在將被include的h檔的內容複製到include此h檔的cpp檔或h檔中,比如說,下面有一個cpp檔跟一個h檔:
cpp:
代碼:
#include "test.h"

void function1()
{
   cout << "test";
}

h:
代碼:
#include <iostream>

void function1();

以上兩個檔案在經過前置處理器處理後,會變成單一個cpp檔,內容如下:
代碼:
#include <iostream>

void function1();

void function1()
{
   cout << "test";
}

應該可以看得出來,#include的作用就是把h檔內的所有內容都複製到cpp檔中。

既然如此,為什麼我們需要h檔呢?全部寫在一個cpp檔中不就得了嗎?

當程式小的時候,我們當然可以只寫在一個cpp檔中,就如我們之前的範例,除了include一些標準的h檔之外,我們並沒有寫出自己的h檔。

但是一但程式越寫越大,行數破千破萬時,如果不將程式分成數個h檔跟cpp檔,那麼就會造成閱讀的困難。

h檔就某方面來說,可以說是跟windows檔案系統中的資料夾是很像的,試想整個windows的檔案全部塞在一起,沒有資料夾去做分類,那會亂到什麼程度,沒有資料夾,自然也不會有桌面或我的最愛等等的功能,數萬個檔案只會全部塞在一起,你想在裡面找到一個你正準備要玩的遊戲的捷徑恐怕都要花上十幾分鐘。

就程式來說也是一樣,如果沒有h檔來分門別類,將程式依函式或類別分成各個小單位,那麼當程式碼行數一多時,就會造成極大的困擾。

當然除此之外,h檔還有其他的功能及意義,不過這稍後再提,先讓我們來看看範例11-1,這是我將範例10-2中main.cpp裡的函式都分開來放到functions.h及functions.cpp做成的專案。

functions.h:(為了方便講解時集中焦點,我在此將註解拿掉)
代碼:
#ifndef FUNCTIONS_H
#define FUNCTIONS_H

#include <iostream>
#include <string>

using namespace std;

const int XMAX = 2;
const int YMAX = 2;

extern long long MyMoney;
extern short status;
extern int moneyOnGround;

void Init( string MapDesc[][YMAX + 1] );
void InputCmd( int &X, int &Y );
void Desc( const string MapDesc[XMAX + 1][YMAX + 1], int X, int Y );
void CoinOrDingDing();
void fight();
void flee();
void drop();
void get( string things = "coins" );

#endif   // #ifndef FUNCTIONS_H

上面一開頭就可以看見兩行奇怪的東西:
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
這也是所謂的前置處理器指令,也就是它會在編譯器真正去編譯這個檔案之前先做某些處理。

ifndef的意思是if not defined也就是如果尚未定義,定義什麼呢?定義後面的FUNCTIONS_H這個符號。由此可知,#ifndef FUNCTIONS_H的意思翻成白話就是如果尚未定義FUNCTIONS_H這個符號,那麼就會接下去執行,如果已經定義了這個符號,自然接下去的內容都不會執行了。

而第二行的意思應該很容易猜到,就是定義FUNCTIONS_H這個符號,這兩行配上最後一行的#endif,就構成了一種功能,也就是讓#ifndef到#endif之中的程式碼只會被#include一次,一但它被include過了,那麼自然就已經執行過#define FUNCTIONS_H,等到第二次再執行到時,在#ifndef判斷的地方,就會跳過去。

那麼為什麼我們需要這樣做呢?什麼情況下它會被include到兩次以上?

當程式一大之後,#include就會使用得很頻繁,而且h檔中也可以include其他h檔,那麼就會發生像是如下的情況:
a.h include b.h
c.h include b.h
d.cpp include a.h & c.h
在這種情況下,d.cpp同時include了a.h跟c.h,它們各自有自己的功能,但它們的功能卻都需要b.h的支援,所以如果沒有#ifndef #define #endif的幫忙,我們在d.cpp中就會重複include b.h兩次,而會造成重複宣告或重複定義之類的錯誤。

因此,在寫每個h檔時,#ifndef #define #endif都是必須的,應該養成良好的習慣,使用這種方式把h檔真正的內容包起來。話說在某些編譯器中,這三行也可以使用#pragma once來代替,只要在程式的最開頭加上#pragma once,在有支援這種寫法的編譯器中自然就會只引用此h檔一次。

待續…

範例下載:
檔案 --- example11-1.rar
說明 --- 將範例10-2中的函式改放到functions.cpp及functions.h裡

檔案 --- functions.rar
說明 --- 將functions.cpp製成functions.lib檔

檔案 --- example11-2.rar
說明 --- 以functions.lib取代範例11-1裡的functions.cpp
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件
Alchemist
偶而上來逛逛的過客


註冊時間: 2010-06-10
文章: 7

130.57 果凍幣

發表發表於: 2010-6-16, PM 12:59 星期三    文章主題: YA - - 又來閒聊了 引言回覆

「一般來說,標頭檔的副檔名是.h,或者.hpp(c++專用),不過微軟提供的很多標頭檔都是沒有副檔名的,像是我們常常引用的iostream,但這並不影響它的功能。 」

這段話我有一些小小地疑惑- -

<> 和 "" 的區別我已經很清楚了這沒有什麼問題

#include <iostream>和#include <iostream.h>

沒有附檔名的寫法我查到的資料是說為了避免和C的函式重疊..(不懂這是啥意思- -)

那既然有.hpp那為何不使用#include <iostream.hpp> <<這種寫法我也從沒看過- -

話說...

C++不是應該要能完全接受C語言的寫法嗎? <<我這句話應該很有問題- -

VC++ 2010裡使用#include <iostream.h>會找不到檔案

而且VC++既然都使用了.cpp這個副檔名了

那為何標頭檔還是使用.h呢?

而且我以為

#include <iostream>

這種寫法只是為了區隔而已...

沒有想到VC++ 2010的include目錄裡的iostream

真的檔名就只有iostream沒有副檔名...

VC6裡則必須寫成#include <iostream.h>

為什麼我覺得應該只要是寫法不同而已

真的連檔名都這樣感覺很怪 - -"
回頂端
檢視會員個人資料 發送私人訊息
yag
Site Admin


註冊時間: 2007-05-02
文章: 688

2673.35 果凍幣

發表發表於: 2010-6-16, PM 7:13 星期三    文章主題: 引言回覆

基本上編譯器不會管你的標頭檔是何副檔名
前置處理器只會根據你的.c、.cc、.cpp、.cxx等檔案裡的#include來引進標頭檔
至於.h或.hpp之類的,都是約定成俗的習慣用法而已
以目前來說,標準委員會已規定所有的標準標頭檔都是無副檔名的
這樣做就是為了跟定此規定前很可能已被世界上許多人使用過的同檔名標頭檔來錯開
至於你說的VC6,那就是定規定前的事,所以它的iostream是有.h的
類似這樣的很多規定都是有歷史因素的
原先的思慮不周在後期為了符合新標準的同時盡量避免影響,就會出現很多匪夷所思的作法
習慣就好
像是…網址為啥要是「http://」開頭?為什麼要用雙斜線?
之前看過篇報導,上面就寫原制定者也說這沒有意義,實際上單斜線或其他方式都可以
只是現在大家都這樣用,要再改就難了
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件
從之前的文章開始顯示:   
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 遊戲程式初級班:語法及基礎概念 所有的時間均為 台灣時間 (GMT + 8 小時)
1頁(共1頁)

 
前往:  
無法 在這個版面發表文章
無法 在這個版面回覆文章
無法 在這個版面編輯文章
無法 在這個版面刪除文章
無法 在這個版面進行投票
可以 在這個版面附加檔案
可以 在這個版面下載檔案


Powered by phpBB © 2001, 2005 phpBB Group
正體中文語系由 phpbb-tw 維護製作