歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C/C++語言中變量作用域:局部變量,全局變量,文件級變量

C/C++語言中變量作用域:局部變量,全局變量,文件級變量

日期:2017/3/1 9:19:27   编辑:Linux編程

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

1.c

const int a = 1;
  • 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++編譯器下均可編譯鏈接成功。

Copyright © Linux教程網 All Rights Reserved