1. 程式人生 > >c語言中static關鍵字用法詳解

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關鍵字宣告,這是一個良好的編碼風格。

無論如何,要在實際編碼時注意自己的編碼習慣,儘量體現出語言本身的優雅和編碼者的編碼素質。