c語言中static關鍵字用法詳解
概述
static關鍵字在c語言中比較常用,使用恰當能夠大大提高程式的模組化特性,有利於擴充套件和維護。
但是對於c語言初學者,static由於使用靈活,並不容易掌握。本文就static在c語言中的應用進行總結,供參考使用。錯漏之處,請不吝指正。
在程式中使用static
變數
1. 區域性變數
普通區域性變數是再熟悉不過的變量了,在任何一個函式內部定義的變數(不加static修飾符)都屬於這個範疇。編譯器一般不對普通區域性變數進行初始化,也就是說它的值在初始時是不確定的,除非對其顯式賦值。
普通區域性變數儲存於程序棧空間,使用完畢會立即釋放。
靜態區域性變數使用static修飾符定義,即使在宣告時未賦初值,編譯器也會把它初始化為0。且靜態區域性變數儲存於程序的全域性資料區,即使函式返回,它的值也會保持不變。
變數在全域性資料區分配記憶體空間;編譯器自動對其初始化
其作用域為區域性作用域,當定義它的函式結束時,其作用域隨之結束
小程式體會一下靜態區域性變數的威力:
#include <stdio.h>
void fn(void)
{
int n = 10;
printf("n=%d\n", n);
n++;
printf("n++=%d\n", n);
}
void fn_static(void)
{
static int n = 10;
printf("static n=%d\n", n);
n++;
printf ("n++=%d\n", n);
}
int main(void)
{
fn();
printf("--------------------\n");
fn_static();
printf("--------------------\n");
fn();
printf("--------------------\n");
fn_static();
return 0;
}
執行結果如下:
-> % ./a.out
n=10
n++=11
--------------------
static n=10
n++=11
--------------------
n=10
n++=11
--------------------
static n=11
n++=12
可見,靜態區域性變數的效果跟全域性變數有一拼,但是位於函式體內部,就極有利於程式的模組化了。
2. 全域性變數
全域性變數定義在函式體外部,在全域性資料區分配儲存空間,且編譯器會自動對其初始化。
普通全域性變數對整個工程可見,其他檔案可以使用extern外部聲明後直接使用。也就是說其他檔案不能再定義一個與其相同名字的變量了(否則編譯器會認為它們是同一個變數)。
靜態全域性變數僅對當前檔案可見,其他檔案不可訪問,其他檔案可以定義與其同名的變數,兩者互不影響。
在定義不需要與其他檔案共享的全域性變數時,加上static關鍵字能夠有效地降低程式模組之間的耦合,避免不同檔案同名變數的衝突,且不會誤使用。
函式
函式的使用方式與全域性變數類似,在函式的返回型別前加上static,就是靜態函式。其特性如下:
- 靜態函式只能在宣告它的檔案中可見,其他檔案不能引用該函式
- 不同的檔案可以使用相同名字的靜態函式,互不影響
非靜態函式可以在另一個檔案中直接引用,甚至不必使用extern宣告
下面兩個檔案的例子說明使用static宣告的函式不能被另一個檔案引用:
/* file1.c */
#include <stdio.h>
static void fun(void)
{
printf("hello from fun.\n");
}
int main(void)
{
fun();
fun1();
return 0;
}
/* file2.c */
#include <stdio.h>
static void fun1(void)
{
printf("hello from static fun1.\n");
}
使用 gcc file1.c file2.c
編譯時,錯誤報告如下:
/tmp/cc2VMzGR.o:在函式‘main’中:
static_fun.c:(.text+0x20):對‘fun1’未定義的引用
collect2: error: ld returned 1 exit status
修改檔案,不使用static修飾符,可在另一檔案中引用該函式:
/* file1.c */
#include <stdio.h>
void fun(void)
{
printf("hello from fun.\n");
}
/* file2.c */
int main(void)
{
fun();
return 0;
}
同樣使用 gcc file1.c file2.c
編譯,編譯通過,執行結果如下:
-> % ./a.out
hello from fun.
面向物件
靜態資料成員
在類內資料成員的宣告前加上static關鍵字,該資料成員就是類內的靜態資料成員。其特點如下:
- 靜態資料成員儲存在全域性資料區,靜態資料成員在定義時分配儲存空間,所以不能在類宣告中定義
- 靜態資料成員是類的成員,無論定義了多少個類的物件,靜態資料成員的拷貝只有一個,且對該類的所有物件可見。也就是說任一物件都可以對靜態資料成員進行操作。而對於非靜態資料成員,每個物件都有自己的一份拷貝。
- 由於上面的原因,靜態資料成員不屬於任何物件,在沒有類的例項時其作用域就可見,在沒有任何物件時,就可以進行操作
- 和普通資料成員一樣,靜態資料成員也遵從
public, protected, private
訪問規則 - 靜態資料成員的初始化格式:
<資料型別><類名>::<靜態資料成員名>=<值>
- 類的靜態資料成員有兩種訪問方式:
<類物件名>.<靜態資料成員名> 或 <類型別名>::<靜態資料成員名>
同全域性變數相比,使用靜態資料成員有兩個優勢:
- 靜態資料成員沒有進入程式的全域性名字空間,因此不存在與程式中其它全域性名字衝突的可能性
- 可以實現資訊隱藏。靜態資料成員可以是private成員,而全域性變數不能
靜態成員函式
與靜態資料成員類似,靜態成員函式屬於整個類,而不是某一個物件,其特性如下:
- 靜態成員函式沒有this指標,它無法訪問屬於類物件的非靜態資料成員,也無法訪問非靜態成員函式,它只能呼叫其餘的靜態成員函式
- 出現在類體外的函式定義不能指定關鍵字static
- 非靜態成員函式可以任意地訪問靜態成員函式和靜態資料成員
總結
static是一個很有用的關鍵字,使用得當可以使程式錦上添花。當然,有的公司編碼規範明確規定只用於本檔案的函式要全部使用static關鍵字宣告,這是一個良好的編碼風格。
無論如何,要在實際編碼時注意自己的編碼習慣,儘量體現出語言本身的優雅和編碼者的編碼素質。