1. 程式人生 > >標頭檔案中定義static靜態變數的利弊

標頭檔案中定義static靜態變數的利弊

對於儲存位置:靜態變數的效果和全域性變數的效果是一樣的,他們都儲存在全域性資料區。頻繁使用其實效率更高,如果定義的靜態變數不用,那就會浪費記憶體,因為全域性資料區生命週期是從程式執行到結束。

區域性變數:每次棧上都要為區域性變數分配空間,因此區域性變數太多會影響效率,但是其回收方便,對於穩定性要求高的系統來說,這樣的操作會更可靠。

全域性變數(包含靜態變數):其空間會在程式啟動時分配好,因此不用不停的分配,頻繁使用更好(當然多執行緒下要同步則會更復雜)。另一點就是它會實實在在的一直佔用記憶體,如果需要太大的記憶體,同時又不會頻繁使用,則建議使用堆變數(特別是嵌入式下記憶體往往不夠用)

堆變數:可動態回收的記憶體,這樣可以實現記憶體使用效率最大化,但是記憶體的分配和管理是需要付出時間的代價,而且使用要比較謹慎,否則容易記憶體洩露,管理很困難。

函式內的靜態變數,說明只有這個函式才用到。只暴露給需要用的人,是一個編碼的好習慣。

問:

一般來說,靜態全域性變數只應該定義在實現檔案中,但有時由於一些特殊的目的,也可能定義在標頭檔案中。比如在有些標準庫的實現中,就用這種方法來初始化標準流cin, cout,或者在在tr1庫中,也用這種方法來定義佔位符。每一個包含該標頭檔案的實現檔案中都擁有該變數的一份拷貝,這些變數放在執行體的data段或者bss段。
比如下面這個變數定義在一個頭檔案中:
static int data[1024*1024];
我把這個檔案同時包含在幾個cpp檔案中,按我的理解,這個程式佔用的記憶體應該顯著增大,但是,從實際執行結果來看,並沒有變化,生成的exe檔案大小也沒有變化,這是因為延遲載入呢,還是被編譯器優化掉了?有沒有明白的達人解釋一下。

答:
這不是編譯器的問題,而是OS的virtual memeory管理機制導致的。資料在實際使用之前,是不會佔用記憶體的——缺頁異常處理程式會為資料分配需要的記憶體。

要理解static,就必須要先理解另一個與之相對的關鍵字,很多人可能都還不知道有這個關鍵字,那就是auto,其實我們通常宣告的不用static修飾的變數,都是auto的,因為它是預設的,就象short和long總是預設為int一樣;我們通常宣告一個變數:
int a;
string s;
其實就是:
auto int a;
auto string s;
而static變數的宣告是:
static int a;
static string s;
這樣似乎可以更有利於理解auto和static是一對成對的關鍵字吧,就像private,protected,public一樣;
對於static的不理解,其實就是對於auto的不理解,因為它是更一般的;有的東西你天天在用,但未必就代表你真正瞭解它;auto的含義是由程式自動控制變數的生存週期,通常指的就是變數在進入其作用域的時候被分配,離開其作用域的時候被釋放;而static就是不auto,變數在程式初始化時被分配,直到程式退出前才被釋放;也就是static是按照程式的生命週期來分配釋放變數的,而不是變數自己的生命週期;所以,像這樣的例子:
void func()
{
int a;
static int b;
}
每一次呼叫該函式,變數a都是新的,因為它是在進入函式體的時候被分配,退出函式體的時候被釋放,所以多個執行緒呼叫該函式,都會擁有各自獨立的變數a,因為它總是要被重新分配的;而變數b不管你是否使用該函式,在程式初始化時就被分配的了,或者在第一次執行到它的宣告的時候分配(不同的編譯器可能不同),所以多個執行緒呼叫該函式的時候,總是訪問同一個變數b,這也是在多執行緒程式設計中必須注意的!
static的全部用法:
1.類的靜態成員:
class A
{
private:
static int s_;
};
在cpp中必須對它進行初始化:
int A::s_ = 0;// 注意,這裡沒有static的修飾!
類的靜態成員是該類所有例項的共用成員,也就是在該類的範疇內是個全域性變數,也可以理解為是一個名為A::s_的全域性變數,只不過它是帶有類安全屬性的;道理很簡單,因為它是在程式初始化的時候分配的,所以只分配一次,所以就是共用的;
類的靜態成員必須初始化,道理也是一樣的,因為它是在程式初始化的時候分配的,所以必須有初始化,類中只是宣告,在cpp中才是初始化,你可以在初始化的程式碼上放個斷點,在程式執行main的第一條語句之前就會先走到那;如果你的靜態成員是個類,那麼就會呼叫到它的建構函式;
2.類的靜態函式:
class A
{
private:
static void func(int );
};
實現的時候也不需要static的修飾,因為static是宣告性關鍵字;
類的靜態函式是在該類的範疇內的全域性函式,不能訪問類的私有成員,只能訪問類的靜態成員,不需要類的例項即可呼叫;實際上,它就是增加了類的訪問許可權的全域性函式:void A::func(int);
靜態成員函式可以繼承和覆蓋,但無法是虛擬函式;
3.只在cpp內有效的全域性變數:
在cpp檔案的全域性範圍內宣告:
static int g_ = 0;
這個變數的含義是在該cpp內有效,但是其他的cpp檔案不能訪問這個變數;如果有兩個cpp檔案聲明瞭同名的全域性靜態變數,那麼他們實際上是獨立的兩個變數;


如果不使用static宣告全域性變數:
int g_ = 0;
那麼將無法保證這個變數不被別的cpp共享,也無法保證一定能被別的cpp共享,因為要讓多個cpp共享一個全域性變數,應將它宣告為extern(外部)的;也有可能編譯會報告變數被重複定義;總之不建議這樣的寫法,不明確這個全域性變數的用法;
如果在一個頭檔案中宣告:
static int g_vaule = 0;
那麼會為每個包含該標頭檔案的cpp都建立一個全域性變數,但他們都是獨立的;所以也不建議這樣的寫法,一樣不明確需要怎樣使用這個變數,因為只是建立了一組同名而不同作用域的變數。
這裡順便說一下如何宣告所有cpp可共享的全域性變數,在標頭檔案裡宣告為extern的:
extern int g_; // 注意,不要初始化值!
然後在其中任何一個包含該標頭檔案的cpp中初始化(一次)就好:
int g_ = 0; // 初始化一樣不要extern修飾,因為extern也是宣告性關鍵字;
然後所有包含該標頭檔案的cpp檔案都可以用g_這個名字訪問相同的一個變數;
4.只在cpp內有效的全域性函式:
在cpp內宣告: static void func();
函式的實現不需要static修飾,那麼這個函式只可在本cpp內使用,不會同其他cpp中的同名函式引起衝突;道理和如果不使用static會引起的問題和第3點一樣;不要在標頭檔案中宣告static的全域性函式,不要在cpp內宣告非static的全域性函式,如果你要在多個cpp中複用該函式,就把它的宣告提到標頭檔案裡去,否則在cpp內部宣告需要加上static修飾;在C語言中這點由為重要!

相關推薦

檔案定義static靜態變數利弊

對於儲存位置:靜態變數的效果和全域性變數的效果是一樣的,他們都儲存在全域性資料區。頻繁使用其實效率更高,如果定義的靜態變數不用,那就會浪費記憶體,因為全域性資料區生命週期是從程式執行到結束。 區域性變數:每次棧上都要為區域性變數分配空間,因此區域性變數太多

[C/C++]在檔案使用static定義變數意味著什麼

宣告:本文乃轉載文章,轉載出處:https://www.cnblogs.com/computer1-2-3/p/6088388.html看到有一位同學在標頭檔案中這麼寫:1 static const wchar_t* g_str1 = … 2 static const wch

全域性變數檔案定義

        看著標題,定義上面加了一個引號,這個得注意了。怎麼解釋呢,一般而言,變數只能定義在.c檔案中,宣告變數才在.h檔案中。下面就打破常規,把定義變數的語句放在.h檔案中,但是對實際而言,變數定義在標頭檔案中是表面上的。         下面直接給出程式碼,有三個

c++在檔案定義全域性變數時需要注意的地方

我們知道,在 C++(但不是在 C 語言)中,const 限定符對預設儲存型別稍有影響。在預設情況下,全域性變數的連結性為外部的,但 const 全域性變數的連結性為內部的。也就是說,在 C++ 看來,全域性 const 定義就像使用了 static 說明符一樣。

C/C++語言在檔案定義全域性變數

轉載:http://blog.csdn.net/chenqiai0/article/details/8490665 全域性變數可不可以定義在可被多個.C檔案包含的標頭檔案中?為什麼? 可以,在不同的C檔案中以static形式來宣告同名全域性變數。標頭檔案中不可以直接定

不要在檔案定義變數

在寫C程式碼的時候,經常需要在標頭檔案中包含有些預定義的資訊。比如一些結構體的宣告,外部變數,函式的宣告等。 有時候覺得有必要在標頭檔案中定義一些變數,這樣在原始檔中就不需要定義了。但是這樣做,有很大的問題。 比如 //test.h 1 #ifndef _TEST_H

在c++檔案使用static修飾的全域性變數

使用static修飾在標頭檔案中修飾的變數,此時不會產生衝突(用static修飾的全域性變數的作用域為定義的原始檔),在多個原始檔中引用該標頭檔案,等於是在每個原始檔中都定義了該變數一次,而且此變數僅在本原始檔中有效,這樣的使用方式不是本身想要的全域性變數,也浪

能不能在檔案定義全域性變數

首先,這是一篇科普文,所以 比較雜,我儘量寫清楚一些。 1、ANSI C標準是什麼?GNU又是什麼?ld是什麼? ANSI C是C語言的標準規範,是國際標準化組織制定的國際標準。 雖然 ANSI C規範了C語言的實現,但是在實際情況中,各家C語言提供商都會根據平臺的不

為什麼inline函式應該在檔案定義?【轉】

(轉自:https://blog.csdn.net/ronnie_hu/article/details/62238311) inline函式(即行內函數)對編譯器而言必須是可見的,以便能夠在呼叫點展開該函式,與非inline函式不同的是,inline函式必須在呼叫該函式的每個檔案中定義。當然,對

codeblock無法編譯,提示函式沒有定義,但是函式已經 在檔案定義

你在新增檔案時沒有選中Targets。預設情況下,一個工程會有兩個Targets,一個叫Debug,一個叫Release,前者可以除錯,用於開發。後者不能除錯,用於生成最終釋出的軟體。CodeBloc

為什麼inline函式應該在檔案定義

inline函式(即行內函數)對編譯器而言必須是可見的,以便能夠在呼叫點展開該函式,與非inline函式不同的是,inline函式必須在呼叫該函式的每個檔案中定義。當然,對於同一程式的不同檔案,如果inline函數出現的話,其定義必須相同。 正因為如此,建議把

inline函式必須在檔案定義嗎?

前不久在寫程式碼的時候遇到一個link錯誤,程式碼的原型如下所示,基本就是定義了一個基類和派生類,在派生類的一個成員函式中用到了基類定義的一個行內函數。 [cpp] view plaincopyprint? // base.hclass Base  {  protected:     void

const物件為什麼可以在檔案定義

對於標頭檔案中為什麼可以定義const變數(或物件),以及推薦用const代替#define巨集定義,之前一直概念不清晰,今天就總結一下。 之前在網上查過,解釋的都不太到位,或者角度不一樣(從編譯原理、強弱定義?),總之不能清晰理解,發現《C++ Primer》上基本上涵蓋

檔案不能定義變數

標頭檔案中定義全域性變數會出現的問題 =====本文轉載的,在工作中,很受用,特此記錄之。====== 直接在標頭檔案中定義全域性變數,然後有多個檔案包含這個標頭檔案時,編譯通過不了,提示重複定義變數! 在標頭檔案中定義全域性變數時前面加上關鍵字static,此時編譯會通過但是此時全域性

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

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

const變數定義檔案

一。、首先要知道強弱符號 編譯器編譯原始檔時會把原始檔的全域性符號(global symbol)分成強(strong)和弱(weak)兩類傳給彙編器,     而隨後彙編器則將強弱資訊編碼並儲存在目標檔案的符號表中。     那麼何謂強弱呢?編譯器認為函式與初始化了的全域性

檔案的巨集定義 檔案的巨集定義

標頭檔案中的巨集定義     程式碼: 1 #ifndef DSP_ADC_BSP_H_ //防止標頭檔案被重複包含 2 #define DSP_ADC_BSP_H_ 3 4 #ifdef _DSP_

檔案能否進行函式的定義

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

檔案寫類的實現出現函式重複定義的問題

先來做一個實驗,你在一個頭檔案中定義一個類,然後把內中的一個函式的實現寫在這個標頭檔案當中。 //A_test.h #ifndefine _A_TEST_ #define _A_TEST_ class A { void test(); }; void A::test() {

函式放在檔案被多次包含的重定義問題

Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu 轉載請標明來源 例如一個頭檔案headfile.h這樣寫 #pragma once bool Func (){return true;} 在這個標頭檔案被多個地方包含的時候就會出