1. 程式人生 > >C/C++語言中變數作用域:區域性變數,全域性變數,檔案級變數

C/C++語言中變數作用域:區域性變數,全域性變數,檔案級變數

C/C++語言中的變數分為全域性變數和區域性變數。這種劃分方式的依據是變數的可見範圍或者叫做作用域

1 區域性變數

區域性變數指的是定義在{}中的變數,其作用域也在這個範圍內。雖然常見的區域性變數都是定義在函式體內的,也完全可以人為的增加一對大括號來限定變數作用域。

如下所示:

void f()
{
    float x = 0;
    {
        int a;
    }
}

別小看這個作用域問題,這對於C++的影響遠比純C要大。C語言中區域性變數離開作用域時,編譯器會插入一個POP 指令來清理變數佔用的棧空間。而在C++中,除了POP指令,還要呼叫解構函式。

class
MyClass { MyClass(){} ~MyClass(){} }; void f() { { MyClass a; } // 此處會C++編譯器被插入呼叫~MyClass()的程式碼 do_someting(); }

C++編譯器在物件a的作用域結束之前,自動插入呼叫~MyClass()的彙編程式碼。

區域性變數作用域是由編譯器強制實施的,這樣一旦出現作用域外訪問,編譯時就會報錯,從而幫助程式設計師排除錯誤。

2 全域性變數

全域性變數的作用域是整個工程,也就是在所有參與連結的檔案中都是可見的。這就會導致一個問題-名稱衝突。例如下面工程中有3個原始檔main.c, 1.c, 2.c。

main.c

#include <stdio.h>
int main(int argc, char** argv)
{
    return 0;
}

1.c

int a = 1;

2.c

int a = 2;

編譯每個檔案都是可以通過的,但是連結時會報錯,因為1.c和2.c使用了同一個名稱的全域性變數。為此,C語言的全域性變數被給予了極壞的形象。甚至不使用全域性變數的教條在很大範圍內盛行。

然而全域性變數在很多時候還是必須的,至少是使用它會讓問題變得方便。例如當一個變數是很多函式的引數時。

void f1(int a);
void f2(int a);
void
f3(int a);

這樣每次呼叫函式都需要傳遞這個變數a,當這樣的引數個數增多時,會讓人變得發狂。如

void f1(int a, int b, int c, int d, int e);
void f2(int a, int b, int c, float g);
void f3(int a, int b, int c, int d);

這種情況在需要儲存狀態的程式中很常見,如GDI庫,OpenGL庫等。此時採用全域性變數來維護狀態資料是非常好的選擇。C++看到了這種需要,所以索性把這些狀態資料和演算法函式繫結到了一起,形成了的概念,從而簡化了程式碼設計。

3 檔案級變數

很多時候,其實程式設計師需要變數的可見範圍既不是整個工程,也不是函式內部,而是在當前檔案中可見。C語言為此提供了靜態全域性變數。static global variable。這個名稱完全沒有能夠反映出變數作用域的範圍,是一個非常糟糕的名字。而且起關鍵字static更是讓人摸不著頭腦。

static int a = 100;

C語言的設計者或許是為了節省關鍵字的使用,很多關鍵字用在不同的地方都有完全不同的含義。這種設計應該是仁者見仁的事情,我個人覺得如果此處使用其他的關鍵字如internal來標識,會更容易讓人理解。

internal int a = 100;

好像在C#中確實存在類似的關鍵字來表示作用域。

言歸正傳,static 修飾的全域性變數只在定義它的檔案內部有效,其他檔案內無法引用它。上面的例子改為:
main.c

#include <stdio.h>
int main(int argc, char** argv)
{
    return 0;
}

1.c

static int a = 1;

2.c

int a = 2;

此時,專案會連結成功。因為全域性範圍內只有一個名為a值為2的全域性變數,值為1的那個a只在1.c內有效。

4 C和C++編譯器對const常量的一點不同

C++編譯器對const常量會自動增加static關鍵字,使其作用域為檔案級別。而C語言編譯器則不會。如下程式碼:

main.c

#include <stdio.h>
int main(int argc, char** argv)
{
    return 0;
}

1.c

const int a = 1;

2.c

int a = 2;

使用C++編譯器可以順利編譯連結成功,但是使用C編譯器則在連線時報錯。為了程式碼的可移植性,最好還是手動把 static const都寫上。

main.c

#include <stdio.h>
int main(int argc, char** argv)
{
    return 0;
}

1.c

static const int a = 1;

2.c

int a = 2;

上述程式碼則在C和C++編譯器下均可編譯連結成功。

相關推薦

no