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文件中。
ui

test.h spa

#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預編譯文件 code

# 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頭文件去除,不然會在編譯過程當中出現重定義錯誤。 遞歸

一些思考:
一、.h頭文件的做用只出如今預編譯階段,預編譯後.h文件就失去了價值,也就是說一個.cpp文件爲一個編譯單元,一個.cpp文件最終生成一個.o文件
二、.h頭文件應該包含些什麼?
a. 包含聲明、條件預編譯指令以及類的定義(類的定義必定要有條件預編譯指令,不然多個文件包含會出現重定義錯誤)
b. 包含須要的的頭文件,無關的頭文件都不須要包含,cpp使用的頭文件都放入cpp文件中,或者單獨創建一個整體的頭文件包含全部須要使用的頭文件
c. 包含常量(包括const常量聲明,定義放在源文件中)和宏定義
ip


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

local_comm.h it

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

test1.cpp io

#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全局變量時,都把它放在原文件中而不是頭文件,這樣就不會給其餘模塊形成沒必要要的信息污染。
相關文章
相關標籤/搜索