1. 程式人生 > >C語言中的static 詳細分析

C語言中的static 詳細分析

          google了近三頁的關於C語言中static的內容,發現可用的資訊很少,要麼長篇大論不知所云要麼在關鍵之處幾個字略過,對於想挖掘底層原理的初學者來說參考性不是很大。所以,我這篇博文博採眾家之長,把網際網路上的資料整合歸類,並親手編寫程式驗證之。

         C語言程式碼是以檔案為單位來組織的,在一個源程式的所有原始檔中,一個外部變數(注意不是區域性變數)或者函式只能在一個源程式中定義一次,如果有重複定義的話編譯器就會報錯。伴隨著不同原始檔變數和函式之間的相互引用以及相互獨立的關係,產生了extern和static關鍵字。

        下面,詳細分析一下static關鍵字在編寫程式時有的三大類用法:

        一,static全域性變數

           我們知道,一個程序在記憶體中的佈局如圖1所示:

      其中.text段儲存程序所執行的程式二進位制檔案,.data段儲存程序所有的已初始化的全域性變數,.bss段儲存程序未初始化的全域性變數(其他段中還有很多亂七八糟的段,暫且不表)。在程序的整個生命週期中,.data段和.bss段內的資料時跟整個程序同生共死的,也就是在程序結束之後這些資料才會壽終就寢。

     當一個程序的全域性變數被宣告為static之後,它的中文名叫靜態全域性變數。靜態全域性變數和其他的全域性變數的儲存地點並沒有區別,都是在.data段(已初始化)或者.bss段(未初始化)內,但是它只在定義它的原始檔內有效,其他原始檔無法訪問它

。所以,普通全域性變數穿上static外衣後,它就變成了新娘,已心有所屬,只能被定義它的原始檔(新郎)中的變數或函式訪問。

以下是一些示例程式

file1.h如下:

#include <stdio.h>

void printStr();

我們在file1.c中定義一個靜態全域性變數hello, 供file1.c中的函式printStr訪問.

#include "file1.h"

static char* hello = "hello cobing!";

void printStr()
{
	printf("%s\n", hello);
}

file2.c是我們的主程式所在檔案,file2.c中如果引用hello會編譯出錯

#include "file1.h"

int main()
{
	printStr();
	printf("%s\n", hello);
	return 0;
}

報錯如下:

[[email protected] static]$ gcc -Wall file2.c file1.c -o file2
file2.c: In function ‘main’:
file2.c:6: 錯誤:‘hello’ 未宣告 (在此函式內第一次使用)
file2.c:6: 錯誤:(即使在一個函式內多次出現,每個未宣告的識別符號在其
file2.c:6: 錯誤:所在的函式內只報告一次。)


如果我們將file2.c改為下面的形式:

#include "file1.h"

int main()
{
	printStr();
	return 0;
}

則會順利編譯連線。

執行程式後的結果如下:
[[email protected] static]$ gcc -Wall file2.c file1.c -o file2
[[email protected] static]$ ./file2
hello cobing!

上面的例子中,file1.c中的hello就是一個靜態全域性變數,它可以被同一檔案中的printStr呼叫,但是不能被不同原始檔中的file2.c呼叫。

      二,static區域性變數

      普通的區域性變數在棧空間上分配,這個區域性變數所在的函式被多次呼叫時,每次呼叫這個區域性變數在棧上的位置都不一定相同。區域性變數也可以在堆上動態分配,但是記得使用完這個堆空間後要釋放之。

       static區域性變數中文名叫靜態區域性變數。它與普通的區域性變數比起來有如下幾個區別:

           1)位置:靜態區域性變數被編譯器放在全域性儲存區.data(注意:不在.bss段內,原因見3)),所以它雖然是區域性的,但是在程式的整個生命週期中存在。

           2)訪問許可權:靜態區域性變數只能被其作用域內的變數或函式訪問。也就是說雖然它會在程式的整個生命週期中存在,由於它是static的,它不能被其他的函式和原始檔訪問。

           3):靜態區域性變數如果沒有被使用者初始化,則會被編譯器自動賦值為0,以後每次呼叫靜態區域性變數的時候都用上次呼叫後的值。這個比較好理解,每次函式呼叫靜態區域性變數的時候都修改它然後離開,下次讀的時候從全域性儲存區讀出的靜態區域性變數就是上次修改後的值。
以下是一些示例程式:

     file1.h的內容和上例中的相同,file1.c的內容如下:

#include "file1.h"

void printStr()
{
	int normal = 0;
	static int stat = 0;	//this is a static local var
	printf("normal = %d ---- stat = %d\n",normal, stat);
	normal++;
	stat++;
}

為了便於比較,我定義了兩個變數:普通區域性變數normal和靜態區域性變數stat,它們都被賦予初值0;

file2.c中呼叫file1.h:

#include "file1.h"

int main()
{
 printStr();
 printStr();
 printStr();
 printStr();
 printf("call stat in main: %d\n",stat);
 return 0;
}

這個呼叫會報錯,因為file2.c中引用了file1.c中的靜態區域性變數stat,如下:

[[email protected] static]$ gcc -Wall file2.c file1.c -o file2
file2.c: In function ‘main’:
file2.c:9: 錯誤:‘stat’ 未宣告 (在此函式內第一次使用)
file2.c:9: 錯誤:(即使在一個函式內多次出現,每個未宣告的識別符號在其
file2.c:9: 錯誤:所在的函式內只報告一次。)

編譯器說stat未宣告,這是因為它看不到file1.c中的stat,下面注掉這一行:

#include "file1.h"

int main()
{
	printStr();
	printStr();
	printStr();
	printStr();
//	printf("call stat in main: %d\n",stat);
	return 0;
}

[[email protected] static]$ gcc -Wall file2.c file1.c -o file2
[[email protected] static]$ ./file2
normal = 0 ---- stat = 0
normal = 0 ---- stat = 1
normal = 0 ---- stat = 2
normal = 0 ---- stat = 3

執行如上所示。可以看出,函式每次被呼叫,普通區域性變數都是重新分配,而靜態區域性變數保持上次呼叫的值不變。

需要注意的是由於static區域性變數的這種特性,使得含靜態區域性變數的函式變得不可重入,即每次呼叫可能會產生不同的結果。這在多執行緒程式設計時可能會成為一種隱患。需要多加註意。


       三,static函式
              相信大家還記得C++面向物件程式設計中的private函式,私有函式只有該類的成員變數或成員函式可以訪問。在C語言中,也有“private函式”,它就是接下來要說的static函式,完成面向物件程式設計中private函式的功能。

            當你的程式中有很多個原始檔的時候,你肯定會讓某個原始檔只提供一些外界需要的介面,其他的函式可能是為了實現這些介面而編寫,這些其他的函式你可能並不希望被外界(非本原始檔)所看到,這時候就可以用static修飾這些“其他的函式”。

           所以static函式的作用域是本原始檔,把它想象為面向物件中的private函式就可以了。

下面是一些示例:

file1.h如下:

#include <stdio.h>

static int called();
void printStr();

file1.c如下:

#include "file1.h"

static int called()
{
	return 6;
}
void printStr()
{
	int returnVal;
	returnVal = called();
	printf("returnVal=%d\n",returnVal);
}

file2.c中呼叫file1.h中宣告的兩個函式,此處我們故意呼叫called():

#include "file1.h"

int main()
{
	int val;
	val = called();
	printStr();
	return 0;
}

編譯時會報錯:

[[email protected] static]$ gcc -Wall file2.c file1.c -o file2
file1.h:3: 警告:‘called’ 使用過但從未定義
/tmp/ccyLuBZU.o: In function `main':
file2.c:(.text+0x12): undefined reference to `called'
collect2: ld 返回 1

因為引用了file1.h中的static函式,所以file2.c中提示找不到這個函式:undefined reference to 'called'

下面修改file2.c:

#include "file1.h"

int main()
{
	printStr();
	return 0;
}

編譯執行:

[[email protected] static]$ gcc -Wall file2.c file1.c -o file2
[[email protected] static]$ ./file2
returnVal=6

       static函式可以很好地解決不同原檔案中函式同名的問題,因為一個原始檔對於其他原始檔中的static函式是不可見的。

有疏漏的地方望各位多多指教~~

相關推薦

C言中static關鍵字的作用

編譯 size lac 所有 指針 變量 運行時 http 多個 在C語言中static的作用如下 第一、在修飾變量的時候,static修飾的靜態局部變量只執行一次,而且延長了局部變量的生命周期,直到程序運行結束以後才釋放。 第二、static修飾全局變量的時候,這個全局變

C言中static修飾的函式和普通函式的區別

用static修飾的函式,本限定在本原始碼檔案中,不能被本原始碼檔案以外的程式碼檔案呼叫。而普通的函式,預設是extern的,也就是說,可以被其它程式碼檔案呼叫該函式。 在函式的返回型別前加上關鍵字static,函式就被定義成為靜態函式。普通 函式的定義和宣告預設情況下是extern的,但靜

C言中static關鍵字的作用詳解

在C語言中,static的字面意思很容易把我們匯入歧途,其實它的作用有三條。 (1)先來介紹它的第一條也是最重要的一條:隱藏。 當我們同時編譯多個檔案時,所有未加static字首的全域性變數和函式都具有全域性可見性。為理解這句話,我舉例來說明。我們要同時編譯兩個原始檔,一個是a.c,另一個是

C言中static全域性變數與普通的全域性變數區別

下面是中興通訊2012校招筆試題的一道問答題: 1. static全域性變數與普通的全域性變數有什麼區別 ?   全域性變數(外部變數)的說明之前再冠以static 就構成了靜態的全域性變數。   全域性變數本身就是靜態儲存方式, 靜態全域性變數當然也是靜態儲存方式。 這兩者在儲存方式上

C言中static的常見作用

有興趣學習c/c++程式設計的小夥伴可以進群:941636044 一起交流哦~ C程式一直由下列部分組成: 1)正文段——CPU執行的機器指令部分;一個程式只有一個副本;只讀,防止程式由於意外事故而修改自身指令; 2)初始化資料段(資料段)——在程式中所有賦了初值的

c言中static關鍵字用法詳解

概述 static關鍵字在c語言中比較常用,使用恰當能夠大大提高程式的模組化特性,有利於擴充套件和維護。 但是對於c語言初學者,static由於使用靈活,並不容易掌握。本文就static在c語言中的應用進行總結,供參考使用。錯漏之處,請不吝指正。 在程

c言中static和auto的區別

1、static變數存放在靜態儲存區,在程式整個執行期間都不釋放;而auto變數存放在動態儲存區,隨著生命週期的結束而立即釋放。 2、static變數只賦值一次,以後就不用賦值;而auto變數在函式每呼叫一次都要賦初值

C言中static的含義和用法

———————————– 測試環境:linux 開發語言:c 編譯工具:gcc ———————————– static 顧名思義是靜態、靜止的意思 個人理解的含義是私有、靜態 私有就是隱藏-> 1.static函式只能聲明後的本文中呼叫

C言中static的作用及C語言中使用靜態函式有何好處

在C語言中,static的字面意思很容易把我們匯入歧途,其實它的作用有三條,分別是: 一是隱藏功能,對於static修飾的函式和全域性變數而言 二是保持永續性功能,對於static修飾的區域性變數而言。 三是因為存放在靜態區,全域性和區域性的static修飾的變數,都預設初始化為0 下面我逐一給

C言中static與extern的用法

在C語言中,static與extern的用法 (1)修飾區域性變數 a.一般情況下,對於區域性變數是存放在棧區的,並且區域性變數的生命週期在該語句塊執行結束時便結束了。但是如果用static進行修飾的話,該變數便存放在靜態資料區,其生命週期一直持續到整個程式

C言中static 函式除了不能再外部被呼叫外和普通函式還有什麼區別呢?

iThinks:本文來自CSDN論壇的討論,觀點不一定全對,但值得從這幾個方面考察static。 C程式一直由下列部分組成:       1)正文段——CPU執行的機器指令部分;一個程式只有一個副本;只讀,防止程式由於意外事故而修改自身指令;      2)初始化資料段

【轉載】C言中static 詳細分析

          google了近三頁的關於C語言中static的內容,發現可用的資訊很少,要麼長篇大論不知所云要麼在關鍵之處幾個字略過,對於想挖掘底層原理的初學者來說參考性不是很大。所以,我這篇博文博採眾家之長,把網際網路上的資料整合歸類,並親手編寫程式驗證之。    

C言中static 詳細分析

          google了近三頁的關於C語言中static的內容,發現可用的資訊很少,要麼長篇大論不知所云要麼在關鍵之處幾個字略過,對於想挖掘底層原理的初學者來說參考性不是很大。所以,我這篇博文博採眾家之長,把網際網路上的資料整合歸類,並親手編寫程式驗證之。    

c言中external,static關鍵字用法

static用法: 在C中,static主要定義全域性靜態變數、定義區域性靜態變數、定義靜態函式。 1、定義全域性靜態變數:在全域性變數前面加上關鍵字static,該全域性變數變成了全域性靜態變數。全域性靜態變數有以下特點。 a.在全域性區分配記憶體。 b.如果沒有初始化,其預設值為

C言中static和extern

  怕原作者刪除,所以轉載過來! 原文地址:http://blog.csdn.net/keyeagle/article/details/6708077/          C語言程式碼是以檔案為單位來

(C言中printf函式讀取的具體分析)

(C語言中printf函式讀取的具體分析) 不多說,直接上。printf函式將傳入的資料傳送到記憶體堆區(緩衝區),然後再根據前面的(格式說明符一個個讀取,這樣會造成錯誤) #include<stdio.h> #include<limits.h> #incl

關於c言中malloc和remalloc函式的分析

首先申明,這是本人第一次寫部落格,其目的僅僅是為了加強自己對知識點的掌握,為到達在本子上記筆記的效果 進入正題。對於malloc,它的作用就是為了動態分配空間,像c++中的new一樣。這裡就不說他們兩的區別了。malloc函式有這樣幾個特點。 1.分配的空間地址是連續的,

C言中static

在C語言中,static的字面意思很容易把我們匯入歧途,其實它的作用有三條。 (1)第一個作用:隱藏。 當我們同時編譯多個檔案時,所有未加static字首的全域性變數和函式都具有全域性可見性。為理解這句話,我舉例來說明。我們要同時編譯兩個原始檔,一個是a.c,另一個是mai

C言中static修飾的函式或變數

被static修飾的函式可認為是“區域性函式”,只能被本原始碼檔案訪問。而沒有static關鍵字的函式可認為是全域性函式(可在函式前寫上extern,此關鍵字是預設的,所以可不寫),可跨檔案被訪問。st

C言中char*和char[]用法區別分析

本文例項分析了C語言中char* 和 char []的區別。分享給大家供大家參考之用。具體分析如下: 一般來說,很多人會覺得這兩個定義效果一樣,其實差別很大。以下是個人的一些看法,有不正確的地方望指正。 本質上來說,char *s定義了一個char型的指標,它只知道所指向的