1. 程式人生 > >標頭檔案的重複包含和變數的重複定義

標頭檔案的重複包含和變數的重複定義

 為什麼會出錯呢?按照條件編譯,a.h並沒有重複包含,可是還是提示變數A重複定義了。
在這裡我們要注意一點,變數,函式,類,結構體的重複定義不僅會發生在源程式編譯的時候,在目標程式連結的時候同樣也有可能發生。我們知道c/c++編譯的基本單元是.c或.cpp檔案,各個基本單元的編譯是相互獨立的,#ifndef等條件編譯只能保證在一個基本單元(單獨的.c或.cpp檔案)中標頭檔案不會被重複編譯,但是無法保證兩個或者更多基本單元中相同的標頭檔案不會被重複編譯,不理解?沒關係,還是拿剛才的例子講:
gcc -c b.c -o b.o :b.c檔案被編譯成b.o檔案,在這個過程中,預處理階段編譯器還是會開啟a.h檔案,定義_A_H並將a.h包含進b.c中。
gcc -c c.c -o c.o:c.c檔案被編譯成c.o檔案,在這個過程中,請注意預處理階段,編譯器依舊開啟a.h檔案,此時的_A_H是否已被定義呢?前面提到不相關的.c檔案之間的編譯是相互獨立的,自然,b.c的編譯不會影響c.c的編譯過程,所以c.c中的_A_H不會受前面b.c中_A_H的影響,也就是c.c的_A_H是未定義的
!!於是編譯器再次幹起了相同的活,定義_A_H,包含_A_H。
到此,我們有了b.o和c.o,編譯main.c後有了main.o,再將它們連結起來生成main時出現問題了:
編譯器在編譯.c或.cpp檔案時,有個很重要的步驟,就是給這些檔案中含有的已經定義了的變數分配記憶體空間,在a.h中A就是已經定義的變數,由於b.c和c.c獨立,所以A相當於定義了兩次,分配了兩個不同的記憶體空間。在main.o連結b.o和c.o的時候,由於main函式呼叫了fb和fc函式,這兩個函式又呼叫了A這個變數,對於main函式來說,A變數應該是唯一的,應該有唯一的記憶體空間,但是fb和fc中的A被分配了不同的記憶體,記憶體地址也就不同,main函式無法判斷那個才是A的地址,產生了二義性
,所以程式會出錯。

講了這麼多,那麼到底怎麼樣才能避免重複定義呢?
其實避免重複定義關鍵是要避免重複編譯,防止標頭檔案重複包含是有效避免重複編譯的方法,但是最好的方法還是記住那句話:標頭檔案儘量只有宣告,不要有定義。這麼做不僅僅可以減弱檔案間的編譯依存關係,減少編譯帶來的時間效能消耗,更重要的是可以防止重複定義現象的發生,防止程式崩潰。

相關推薦

檔案重複包含變數重複定義

在c或c++中,標頭檔案重複包含問題是程式設計師必須避免的問題,也是很多新手容易犯錯的問題。為什麼要避免標頭檔案重複包含呢?        1.我們知道在編譯c或c++程式時候,編譯器首先要對程式進行預處理,預處理其中一項工作便是將你源程式中#include的標頭檔案完整的展

檔案重複包含變數重複定義

 為什麼會出錯呢?按照條件編譯,a.h並沒有重複包含,可是還是提示變數A重複定義了。 在這裡我們要注意一點,變數,函式,類,結構體的重複定義不僅會發生在源程式編譯的時候,在目標程式連結的時候同樣也有可能發生。我們知道c/c++編譯的基本單元是.c或.cpp檔案,各個基本單元的編譯是相互獨立的,#ifndef等

linux常用環境變數c/c++檔案/庫路徑環境變數

環境變數設定 /etc/profile:在登入時,作業系統定製使用者環境時使用的第一個檔案,此檔案為系統的每個使用者設定環境資訊,當用戶第一次登入時,該檔案被執行。並從/etc/profile.d目錄的配置檔案中搜集shell的設定。 /etc/bashrc:為每一個執行b

檔案的編寫引用

      我用的是 Dev-c++  編寫標頭檔案     首先寫標頭檔案裡面的函式,       然後儲存,記得字尾寫  .h   就行   例:(順序表的標

ubuntu中找不到檔案term.hcurses.h的解決方法

創建於 2012-05-16 收藏自個人的百度空間 -------------------------------- 當/usr/include中沒有term.h和curses.h時,包含這兩個標頭檔案的程式會如下報錯: term.h: 沒有那個檔案或目錄 curses.h

解決C/C++ 檔案相互包含 問題的方法

http://blog.sina.com.cn/s/blog_6ef9a3ad0101emuw.html http://blog.csdn.net/hazir/article/details/38600419 所謂超前引用是指一個型別在定義之前就被用來定義變數和宣告函式。

關於c++裡面引用檔案尖括號雙引號的使用

今天寫資料庫,因為用的是mysql自帶的c api。設計到庫的匯入和標頭檔案的匯入。 用include 引用標頭檔案時,雙引號和尖括號的區別: 1.雙引號:引用非標準庫的標頭檔案,編譯器首先在程式原始檔所在目錄查詢,如果未找到,則去系統預設目錄查詢,通常用於引用使

檔案中只能宣告變數不能定義變數 而宣告變數必須帶extern,為什麼檔案變數的宣告都沒有加

 1.標頭檔案中不可以放變數的定義!一般標頭檔案中只是放變數的宣告,因為標頭檔案要被其他檔案包含#include,如果把定義放在標頭檔案的話,就不能避免多次定義變數。C++不允許多次定義變數,一個程式中對指定變數的定義只有一次,宣告可以無數次。 三個例外:1)值在編譯時

檔案保護符#pragma once #pragma once與 #ifndef的區別

為了避免同一個檔案被include多次 1   #ifndef方式 2   #pragma once方式 在能夠支援這兩種方式的編譯器上,二者並沒有太大的區別,但是兩者仍然還是有一些細微的區別。     方式一:     #ifndef __SOMEFILE_H__     #define __SOMEFIL

檔案包含以及名稱空間的引入儘量寫在cpp檔案

菜鳥程式設計需要知道的規範。 1,標頭檔案儘量包含在cpp檔案裡,而不是h檔案裡 放在.cpp檔案中是比較安全的,檔案在多次遞迴包含後很容易出現一些定義和宣告上的問題。放在cpp中可以減小標頭檔案依賴,可以提高編譯速度。所以,能放在cpp中的,就不要放在h中。只有標頭

檔案windows.h巨集定義而引發的錯誤

先看下面一段程式碼:#define _CRT_SECURE_NO_WARNINGS 1 #define N 6 #include<stdio.h> #include<Windows.h> int main() { printf("%d \n",

解決檔案相互包含問題的方法

一般情況下,C/C++要求所有的型別必須在使用前被定義,但是在一些特殊情況下,這種要求無法滿足,例如,在類CMyView中保留了一個非模式對話方塊物件指標,該物件用於顯示/修改一些資訊。為了實現對話方塊"應用"按鈕,把對話方塊做的修改立刻更新到view介面上,為此,需要在對話方塊類中需要儲存view類的指標,

C++兩個類檔案互相包含

在構造自己的類時,有可能會碰到兩個類之間的相互引用問題,例如:定義了類A類B,A中使用了B定義的型別,B中也使用了A定義的型別class A{    int i;    B b;}class B{    int i;    A* a;}請注意上面的定義內容,一般情況下是不能出

C++檔案的重定義問題以及檔案互相包含問題

  有的人將重複編譯,重複包含與重複定義弄混,比如:定義一個類,在例項化它之前並不產生記憶體開銷;這與基本型別有所區別。 明明在標頭檔案使用了#pragma once;#ifndef...#defi

預編譯檔案的作用使用方法介紹

預編譯頭的概念: 所謂的預編譯頭就是把一個工程中的那一部分程式碼,預先編譯好放在一個檔案裡(通常是以.pch為副檔名的),這個檔案就稱為預編譯標頭檔案這些預先編譯好的程式碼可以是任何的C/C++程式碼--------甚至是inline的函式,但是必須是穩定的,在工程開發的過

MFC之檔案相互包含問題及解決方法 error C4430: 缺少型別說明符

問題一: error C4430: 缺少型別說明符 - 假定為 int。注意: C++ 不支援預設 int 原因分析: 1. (此情況經常出現在大型工程專案中)如果存在兩個類的標頭檔案a.h和b.h,在a.h中有這樣的語句:#include "b.h",在b.h檔案中有這樣的

c++中兩個類的檔案互相包含編譯出錯的解決辦法

首先我們需要問一個問題是:為什麼兩個類不能互相包含標頭檔案? 所謂互相包含標頭檔案,我舉一個例子:我實現了兩個類:圖層類CLayer和符號類CSymbol,它們的大致關係是圖層裡包含有符號,符號裡定義一個相關圖層指標,具體請參考如下程式碼(注:以下程式碼僅供說明問題,不作為

string.h 檔案包含的一些庫函式

char *strcpy(char* dest, const char *src); 把從src地址開始且含有NULL結束符的字串複製到以dest開始的地址空間.src和dest所指記憶體區域不可以重疊且dest必須有足夠的空間來容納src的字串。返回指向dest的指標

檔案中能否進行函式的定義

通常我們使用標頭檔案時都是在標頭檔案中進行宣告,在原始檔中定義,哪我們能否在標頭檔案中進行函式的定義 我們先進行一個測試,先宣告一個test.h和一個test.cpp檔案,並且在test.h中定義一個函式和一個變數 可以發現,程式執行沒有問題,結果也正確

[undefine reference to...]c++ 已經引用檔案的情況編譯顯示未定義

1.仔細檢查程式碼是否寫錯. 2.反覆檢查第一步,再確認c++是否未註明名稱空間. 3.感覺很坑的一點,就是makefile沒有新增對應的.cpp檔案。有時候一不小心就遺忘了. 4.不要告訴我,你編譯之前沒有儲存檔案(非IDE開發環境). 5.比最坑還坑的一點,確認make