C++中頭文件、源文件之間的區別與聯系


.h頭文件和.cpp文件的區別 
疑惑1:.h文件能夠編寫main函數嗎? 
實驗: 
編寫test.h文件,里面包含main函數 
若直接編譯g++ test.h -o test,通過file命令 file test,得到如下結果test: GCC precompiled header (version 013) for C++ ———test文件是預編譯頭文件 

推測:.h文件不能單獨生成.o文件 

疑惑2:.h文件中聲明和定義的變量和函數是如何與.cpp文件結合的?
實驗:
編寫test.h文件,里面包含一個變量定義以及函數定義,編寫test.cpp文件包含該頭文件,通過g++ -E test.cpp -o test.i生成預編譯文件,打開test.i文件發現,上面包含了頭文件中變量的定義以及函數的定義,就像平時我們可以不寫.h文件,只寫.cpp文件一樣,把所有的聲明和定義都放在了一個.cpp文件中。 


test.h
#ifndef _TEST_H
#define _TEST_H
int var = 1;
void func {
}
#endif
test2.h
#ifndef _TEST2_H
#define _TEST2_H
#include "test.h"
#endif
test.cpp
#include "test.h"
#include "test2.h"
int main ()
{
   var = 2;
   return 0;
}
gcc -E test.cpp -o test.i 得到test.i預編譯文件

# 1 "test.cpp"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "test.cpp"
# 1 "test.h" 1
int var = 1;
void func {
}
# 2 "test.cpp" 2
# 1 "test2.h" 1
# 3 "test.cpp" 2
int main ()  
{
   var = 2;
   return 0;
}

推測:.cpp文件中的#include預編譯指令將.h的文件內容包含進來(#include指令是遞歸執行的),並通過條件預編譯指令#ifndef、#define、#endif將重復的.h頭文件去除,否則會在編譯過程中出現重定義錯誤。 

一些思考:
1、.h頭文件的作用只出現在預編譯階段,預編譯后.h文件就失去了價值,也就是說一個.cpp文件為一個編譯單元,一個.cpp文件最終生成一個.o文件
2、.h頭文件應該包含些什么?
a. 包含聲明、條件預編譯指令以及類的定義(類的定義一定要有條件預編譯指令,否則多個文件包含會出現重定義錯誤)
b. 包含需要的的頭文件,無關的頭文件都不需要包含,cpp使用的頭文件都放入cpp文件中,或者單獨建立一個總體的頭文件包含所有需要使用的頭文件
c. 包含常量(包括const常量聲明,定義放在源文件中)和宏定義 




在頭文件中定義變量或函數會出現什么問題?(全局變量和函數默認是extern屬性) 


local_comm.h

#ifndef _LOCAL_H 
#define _LOCAL_H 
int var = 2; 
void func() {}; 
#endif 
test1.cpp

#include <stdio.h> 
#include "local_comm.h" 
 
void func1()  
{ 
        printf("func1 &var=%lu\n", &var);   
} 
test2.cpp

#include <stdio.h> 
#include "local_comm.h" 
 
void func2()  
{ 
        printf("func2 &var=%lu\n", &var);   
} 
main.cpp

extern void func1(); 
extern void func2(); 
int main() 
{ 
        func1(); 
        func2(); 
} 
g++ main.cpp test1.cpp test2.cpp 編譯報錯
$g++ main.cpp test1.cpp test2.cpp  
/tmp/ccGkEzQE.o: In function `func()': 
test2.cpp:(.text+0x0): multiple definition of `func()' 
/tmp/ccpTecbJ.o:test1.cpp:(.text+0x0): first defined here 
/tmp/ccGkEzQE.o:(.data+0x0): multiple definition of `var' 
/tmp/ccpTecbJ.o:(.data+0x0): first defined here 
collect2: ld returned 1 exit status 

結論:頭文件的條件預編譯指令只能去掉同一個編譯單元中包含的重復定義,不能在鏈接的時候去掉各個編譯單元中的相同的定義,因為普通變量和函數默認屬性是全局的,也就是在整個最后生成的exe中只能有唯一一個同名的變量和函數。 



在頭文件中定義static靜態變量或者靜態函數會出現什么問題?(全局const變量默認是static屬性) 


修改local_comm.h,將變量和函數改成static屬性。

#ifndef _LOCAL_H 
#define _LOCAL_H 
static int var = 2; 
static void func() {}; 
#endif 
編譯運行:

$g++ main.cpp test1.cpp test2.cpp 
$./a.out 
func1 &var=4196096 
func2 &var=4196116 

結論:靜態變量和靜態函數的作用域只是在本編譯單元(.o文件),在不同的副本都保存了該靜態變量和靜態函數,正是因為static有以上的特性,所以一般定義static全局變量時,都把它放在原文件中而不是頭文件,這樣就不會給其他模塊造成不必要的信息污染。 

轉:http://my.oschina.net/fergus/blog/123484 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM