天天看點

【C/C++】關鍵字static

參考自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/19/2598815.html (華山大師兄)

這裡我們隻讨論了C語言的static

首先我們回顧一下各種變量在記憶體中的位置:

【C/C++】關鍵字static

BSS和DATA段都屬于靜态資料區,在程序運作過程中,靜态資料區的資料始終存在。靜态全局變量和其他全局變量的存儲地點沒有差別,是以還是在BSS和DATA中。但是,靜态全局變量僅在定義它的源檔案中有效,其他檔案即使用extern聲明也沒法使用他。準确地說作用域是從定義之處開始,到檔案結尾處結束,在定義之處前面的那些代碼行也不能使用它。

1、靜态的全局變量和函數

當同時編譯多個檔案時,所有未加static字首的全局變量和函數都具有全局可見性。

舉個例子:

//a.c
#include <stdio.h>

char a = 'A';               // global variable
void msg()
{
     printf("Hello\n");
}
           
//a.h
#ifndef _A_H_
#define _A_H_

extern char a;
void msg();

#endif
           
#include <stdio.h>
#include "a.h"

//b.c
int main()
{
     printf("%c ", a);
     msg();
     return 0;
}
           

以上代碼成功編譯連接配接後,輸出 A Hello。

我們知道,所有未加static字首的全局變量和函數都具有全局可見性,其它的源檔案也能通路。此例中,a是全局變量,msg是函數,并且都沒有加static字首,是以對于另外的源檔案b.c是可見的。

但是,如果加了static,就會對其它源檔案隐藏。例如在a和msg的定義前加上static,b.c就看不到它們了。利用這一特性可以在不同的檔案中定義同名函數和同名全局變量,而不必擔心命名沖突。

2、靜态的局部變量

static局部變量在函數内定義,它的生存期為整個程式運作過程,但是其作用域仍與自動變量相同,隻能在定義該變量的函數内使用該變量。退出該函數後, 盡管該變量還繼續存在,但不能使用它。

舉個例子:

#include <stdio.h>

int fun(){
    static int count = 10;       //在第一次進入這個函數的時候,變量a被初始化為10!并接着自減1,以後每次進入該函數,a
    return count--;              //就不會被再次初始化了,僅進行自減1的操作;在static發明前,要達到同樣的功能,則隻能使用全局變量:    

}

int count = 1;

int main(void)
{
     printf("global\t\tlocal static\n");
     for(; count <= 10; ++count)
               printf("%d\t\t%d\n", count, fun());
     return 0;
}
           

輸出如下:

【C/C++】關鍵字static

基于以上兩點,我們得出:把局部變量改變為靜态變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變為靜态變量後是改變了它的作用域, 限制了它的使用範圍。是以static 這個說明符在不同的地方所起的作用是不同的。

3、未手動初始化的static變量和全局變量預設初始化為0

未手動初始化的static變量和全局變量都存儲在 BSS 段,該區域的變量的值都為0。

某些時候這一特點可以減少程式員的工作量。比如初始化一個稀疏矩陣,我們可以一個一個地把所有元素都置0,然後把不是0的幾個元素指派。如果定義成靜态的,就省去了一開始置0的操作。再比如要把一個字元數組當字元串來用,但又覺得每次在字元數組末尾加‘\0’;太麻煩。如果把字元串定義成靜态的,就省去了這個麻煩,因為那裡本來就是‘\0’;不妨做個小實驗驗證一下。

#include <stdio.h>

int a;

int main()
{
     int i;
     static char str[10];
     printf("integer: %d; string: (begin)%s(end)", a, str);
     return 0;
}
           

運作結果為:integer: 0; string: (begin) (end)