#ifndef 解決局部變量定義的問題——共享文件頭導致重定義問題

C++ - Shared Header Causes Multiply Defined Symbol Error

今天遇到一個多重定義問題,自己寫了個小程序實驗了下,

一個頭文件head.h定義了一個字符串常量。兩個cpp,main.cpp,source.cpp  都include head.h文件

Complie能過Link的時候報錯了,vc 報的錯誤是:error LNK2005: "char const * const pchar" (?pchar@@3PBDB) already defined in main.obj

頭文件head.h代碼如下:

#ifndef _HEAD_J_H

#define _HEAD_J_H

const char * pchar = "123456";

#endif _HEAD_J_H

思考一:

爲什麼我已經加了#ifndef了還是會導致 重定義,#ifndef #define ....#endif的作用不是防止重定義麼?

跟小菊同學討論之後,他說#ifndef防止重定義是在單個obj內的,即如果單個cpp文件多次包含某一頭問題只會編譯一次,但是如果有多個cpp文件,#ifndef只會限制每個cpp文件內的頭文件不會包含多次,幾個cpp文件之間是不會有影響的。我查了《windows核心編程》這本書裏有講編譯鏈接生成exedll的過程。編譯過程中每個cpp都會編譯生成一個對應obj文件,鏈接過程中將每個obj連接起來生成一個可執行文件。我又查了《c++primer》關於#ifndef的內容,裏面提到了是爲了防止編譯過程,看清楚是編譯過程中防止頭文件被多重定義,所以#ifndef確實只會限制單個obj文件裏頭文件不被包含多次;


思考二:

我將上面的head.h的代碼改爲如下的卻complielink都成功了

#ifndef _HEAD_J_H #define _HEAD_J_H const char ch = 'd'; #endif _HEAD_J_H

說好的重定義呢?怎麼又沒了呢?修改之前和修改之後唯一的區別是變量chconst類型,和pchar只是指向const 內容的指針,卻不是const 類型指針, 於是乎我又將代碼改爲如下:

#ifndef _HEAD_J_H #define _HEAD_J_H //void func(); const char * const pchar = "123456"; #endif _HEAD_J_H

將指針也變爲const類型,就又成功了。照理說 既然我這麼定義在頭文件裏 肯定是global變量了,在main.cpp裏定義了一次在source.cpp裏定義了一次,在鏈接obj的時候發現有兩個 同樣的變量,這個時候必然會報重定義錯誤。但是改爲const類型之後爲什麼不報錯了呢,我去查了《c++primer》裏面有關const內容的,裏面有一段話是大致是這樣寫的:

C++中的const對象默認爲文件的局部變量,與其他變量不同,不特殊申明的話,在全局作用域內的const變量定義該對象文件的局部變量,此變量只存在於那個文件中,不能被其他文件訪問,其他文件訪問需要加extern

看了上面的解釋,相信大家也都知道了原因了,既然作爲局部變量了,幾個cpp文件link的時候當然不會出錯了。這也是const的特性吧,這是一種解決 頭文件裏變量重定義的方法;


思考三:

我們大部分在頭文件裏定義 變量 基本都是常量,大家可以用#define 宏定義來解決問題,宏定義 內容是存儲在代碼段的,在編譯之前做文本替換。宏定義的一個確定 就是 類型檢查 ,各有優弊吧,大家自行選擇;


思考四:

在網上搜索資料的時候還發現了一種方法,就是將cpp文件改爲.c文件,這樣就會按照語言編譯,在C語言中,如果遇到多個 比如說是 int i 吧,會將第一個作爲定義,其他的都作爲聲明,所以不會出錯;


總結:一般來說C++裏不建議你在頭文件裏定義變量的,所以大家還是能移則移到cpp吧,然後用extern來支持多個文件訪問;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章