簡體   English   中英

C和C ++中的靜態變量

[英]Static variables in C and C++

在C和C ++之間的任何函數之外聲明為static的變量之間是否有任何區別。 我讀到static意味着文件范圍,並且文件外部不能訪問變量。 我還讀到在C中,全局變量是static 那么這是否意味着C中的全局變量無法在另一個文件中訪問?

不,在這方面C和C ++沒有區別。

閱讀這個關於C程序中static含義的答案 在C ++中,還有一些與使用static類變量(而不是實例變量)相關的其他含義。

關於全局變量是static - 僅從內存分配的角度來看(它們被分配在數據段上,就像所有全局變量一樣)。 從可見性的角度來看:

static int var;    // can't be seen from outside files
int var;           // can be seen from outside files (no 'static')

這里有兩個概念“靜態鏈接 (或范圍)”和靜態分配 “。

在函數外部,關鍵字指的是鏈接,里面指的是分配。 函數外的所有變量都隱式地具有靜態分配。 也許是一個不幸的設計,但確實如此。

C和C ++是一樣的。

static做了兩件不同的事情。

對於在函數作用域外聲明的變量,它會更改變量的可見性(鏈接)。 變量將是一個全局變量,因為它在函數范圍之外。 如果它不是靜態的,它將具有通用鏈接(可見性),因此與此鏈接在一起的任何代碼都可以訪問它(它們可能必須將其聲明為extern)。 如果變量在函數作用域之外並且是靜態的,它仍然是一個全局變量,因為它始終存在並保持其值,但是在同一編譯單元(.c文件和包含的任何.h)之外的代碼都不能訪問它。

對於在函數作用域內聲明的變量,static會更改存儲變量的位置。 如果它不是靜態的,它將是一個自動變量,這意味着它會隨着函數的退出而消失,並在再次輸入函數時重新出現(在堆棧中)。 退出函數時它會丟失它的值。 並且在函數退出后,對它的任何引用(指向它)都是無效的。 如果在函數作用域內聲明的變量是靜態的,那么它使它不是自動變量而是全局分配的變量。 因此,變量將在函數退出后存在,因此將在函數的調用中保持其值,並且即使在函數退出之后,對它的任何引用(指針)也是有效的。 請注意,在這兩種情況下,變量的范圍僅在該函數內,因此無法從函數范圍外直接訪問它(但僅通過保存的引用)。

靜態做的最后一件事是在運行變量的初始值設定項(即int foo = 5)時進行更改。 對於分配是全局的所有情況(除了自動分配之外的每種情況),初始化程序僅在程序執行開始時運行一次。 它在main()運行之前運行,因此如果初始化程序不僅僅是一個常數而是運行一些代碼,那么你可以得到一些不太理想的結果。 對於自動情況,每次輸入函數時都會運行初始化程序,在這種情況下,它始終在輸入main()之后運行。

我想在C和C ++中添加Southern Hospitality的回答靜態變量

以下評論:

在C ++中不推薦使用static來表示“本地到翻譯單元”(href =“https://rads.stackoverflow.com/amzn/click/com/0201700735”rel =“nofollow noreferrer”C ++編程語言:特殊版本,附錄B.2.3,不推薦使用的功能)。

您應該使用未命名的命名空間:

static int reply = 42; // deprecated

namespace {
    int reply1 = 42;  // The C++ way
}

正如Southern Hospitality所說,全局對象的初始化順序是不確定的。 在這種情況下,您應該考慮使用單點模式的href =“http://en.wikipedia.org/wiki/Singleton_pattern#C.2B.2B”。

更新:GMan評論我的回答:

“訂單是按翻譯單位定義的,......”:這真的讓我不知所措,所以我在C ++編程語言中查了一下。

在第9.4.1節“非局部變量的初始化”中,Stroustrup教授建議“返回引用的函數是全局變量的一個很好的替代”:

int& use_count()
{
        static int uc = 0;
        return uc;
}

“對use_count()調用現在充當首次使用時初始化的全局變量。例如:”

void f()
{
        std::cout << ++use_count() << '\n';
}

據我所知,這與Singleton模式非常相似。

GMan進一步評論說:“我們需要限制我們創建這些對象的能力,並提供對它的全局訪問。” 對一個人的限制是否真的與問題中的任何事情有關? 我們可能需要全球一個,但是誰說我們不想在其他地方使用它?“

Singleton(127)(Gamma等,Design Patterns)的一些引用:

“Singleton模式是對全局變量的改進。它避免了使用存儲唯一實例的全局變量來污染名稱空間。”

“這種模式可以讓你輕松改變主意,並允許使用Singleton類的多個實例。”

單身人士按照他們第一次使用的順序進行初始化。

在Herb Sutter,Andrei Alexandrescu,C ++編碼標准中,第10項說:

“避免共享數據,尤其是全球數據。”

因此,我經常使用單身人士來避免全球數據。 但是,當然,由於一切都是可以過度使用的,這可能是過度使用Singleton模式。 (Johshua Kerievsky在他的“Refactoring to Patterns”一書中稱之為“單身性炎症”。)

更新2:

(對不起,但我不能寫評論,因此這個更新。)

賈爾夫在評論中寫道:“當他們撰寫有關單身人士模式的文章時,四人幫在吸食非法行為。”

顯然,其他C ++開發人員也吸食了有趣的物質。 例如,Herb Sutter(他在第二個C ++標准,C ++ 0x開發期間擔任ISO C ++標准委員會秘書和主席十多年,並在Microsoft擔任C ++ / CLI的首席架構師.Herb目前用於Microsoft平台的Prism內存模型的設計者和用於並行編程的Visual C ++的Concur擴展,在C ++編碼標准中寫道,第21項:

“當你需要一個可能依賴於另一個的(命名空間級別)變量時,請考慮Singleton設計模式;仔細使用它可以通過確保在第一次訪問時初始化對象來避免隱式依賴。但是,Singleton是一個全局變量綿羊的衣服,被相互或循環的依賴打破。“

因此,如果可以,請避免使用全局數據。 但是,如果必須在單獨的轉換單元中使用全局數據,則Singleton應該是可執行特定初始化序列的可接受解決方案。

請注意,在Java語言中,全局數據甚至不存在。 顯然,使用Singleton設計模式替代/模擬全局數據。

(因為我在Java團隊的日常工作中工作,我努力使我的C ++程序與Java程序最大程度地相似。例如,每個類都位於其自己的源文件/翻譯單元中。)

對你的問題不是一個直接的答案,但如果你同時使用C和C ++,那么要注意與之密切相關。

在C ++中,與C不同,聲明為“const”的全局變量對於轉換單元是隱式本地的,因為AS IF使用了“靜態”。

例:

// file A
extern const int glob;

// file B
const int glob = 42;

如果您使用C編譯器但不使用C ++編譯器,這將起作用。 在C ++中,文件B中的glob變量不能在文件A中使用,鏈接器將生成“未解析的引用”錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM