1. 程式人生 > >C++中static和extern的微妙細節

C++中static和extern的微妙細節

static和extern在C和C++中可以用來既可以修飾資料(變數和常量),還可以修飾函式。
      如果用來修飾變數常量資料識別符號,則static和extern的時間特性(儲存特性)相同的,都是靜態儲存,儲存在全域性資料區,但是static是在定義時生成,而extern則是在程式執行前已經建立(早於main()函式執行),一直到程式結束銷燬,但是static要早於extern,所以MFC採用全域性xxApp類物件中main()啟動程式,而Java語言採用靜態Main類物件中main()啟動程式都是可行的;而它們的空間特性(作用域)不同,static識別符號是通常指區域性資料(靜態全域性變數(常量)指是約束在內部變數(常量);靜態區域性變數和常量是塊作用域;類靜態資料成員則是類作用域,受類訪問約束符控制,但是被所有類物件共享;不同於普通類資料成員每個類物件都要建立其記憶體副本),而extern識別符號是全域性資料(全域性變數和常量,具有檔案作用域,通過包含其宣告檔案,可以被其它檔案訪問,不能用於類資料成員)。
     如果用來修飾函式,則static函式和extern函式的時間特性(儲存特性)也是相同的,都是靜態儲存,也是程式執行時就已經存在記憶體;而其空間特性(作用域)不同,static指內部函式,侷限在檔案內部使用,而extern指外部函式,通過include標頭檔案(介面),可以被其它檔案使用。
     實際使用要注意:static,extern通常加在變數、常量宣告和函式宣告前面,除非是定義和宣告合二為一的,才加在定義前;一般在函式外部定義的都預設為extern全域性的(變數、常量),普通函式也預設為extern(外部)的,因此要宣告為靜態變數、常量或者static內部函式必須顯式指定,而且static內部函式通常宣告在CPP檔案中,以達到隱藏介面,防止和其它同名外部函式名字衝突。例如:
gloab.h

#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED
extern int Gloab_Int;  //全部變數宣告
#endif // TEST_H_INCLUDED

gloab.cpp

#include "gloab.h"
int Gloab_Int = 1000;

print.h

#ifndef PRINT_H_INCLUDED
#define PRINT_H_INCLUDED
extern void print();
#endif // PRINT_H_INCLUDED

print.cpp

#include "print.h"
#include "test.h"
#include

static void printStatic();  //內部介面必須在cpp檔案中宣告,或者先定義在呼叫。

void print()
{
     Gloab_Int += 1000;
     std::cout << "Gloab_Int = " << Gloab_Int << std::endl;
     printStatic();
}

int gInit = 10;           //全域性變數沒有在標頭檔案宣告釋放介面,不能為外部檔案使用,而且外部檔案不能存在同名外部全域性變數
static int sgInit = 100;  //靜態變數,表示其為內部變數,不能釋放宣告,為外部檔案使用;
                                  //可以存在同名的外部全域性變數,只要不在本檔案中直接或間接包含其標頭檔案

void printStatic()
{
    int iTemp = 0;
    static int siVal = 1;
    std::cout << "iTemp = " << iTemp++ << std::endl;
    std::cout << "siVal = " << siVal++ << std::endl;
    std::cout << "gInit = " << gInit++ << std::endl;
    std::cout << "sgInit = " << sgInit++ << std::endl;
}

externprint.h

#ifndef EXTERNPRINT_H_INCLUDED
#define EXTERNPRINT_H_INCLUDED
extern void printStatic();
extern int sgInit;     //和內部靜態全域性變數名字不衝突
//extern int gInit;    //全域性變數名字衝突
#endif // EXTERNPRINT_H_INCLUDED

externprint.cpp

#include "externPrint.h"
#include "test.h"
#include

int sgInit = 1;
//int gInit = 10;

void printStatic()
{
    std::cout << "Gloab_Int = " << ++Gloab_Int << std::endl;
}