理解c語言存儲類

    C語言使用作用域、鏈接和存儲時期來定義5種存儲類:自動、寄存器、具有代碼塊作用域的靜態、具有外部鏈接的靜態,以及具有內部鏈接的靜態。

存儲類 時期 作用域 鏈接 聲明方式
自動 自動 代碼塊 代碼塊內
寄存器 自動 代碼塊 代碼塊內,使用關鍵字register
具有外部鏈接的靜態 靜態 文件 外部 所有函數之外
具有內部鏈接的靜態 靜態 文件 內部 所有函數之外,使用關鍵字static
空鏈接的靜態 靜態 代碼塊 代碼塊內,使用關鍵字static

    我想大概可以不嚴謹的把相關概念與生活中的足球籃球運動做比較。先介紹一下背景吧,CPU、內存、硬盤分別對應比賽場、更衣室和酒店。平時數據就安安靜靜的躺在硬盤,需要計算時就來到內存做準備,整個計算過程在CPU中進行,計算結束後,數據首先回到內存,最後再返回硬盤。硬盤的數據是“靜”的,CPU/內存的數據是“動”的,其中CPU分爲計算器,控制器,寄存器和時鐘,計算器的運行就相當於正在進行激烈的比賽,寄存器就是替補席,存放隨時可能用到的數據。
    介紹完背景知識,可以進行基本概念的介紹了。變量和函數都可以分成不同的存儲類,一個變量就相當於一名賽場上的運動員,函數就是戰術,沒錯,類似“牛角”、“鑽石”這樣的戰術。函數需要若干個變量來參與執行。“時期”和“作用域”分別是從時間和空間的角度進行定義的。時期分爲自動和靜態,自動意味着變量根據函數的需要靈活進行定義、使用和釋放,就像運動員執行完相應戰術,就可以下場休息了,戰術需要的時候再上場;而靜態表示變量被定義之後就一直持續到程序結束,就像運動員上場之後就一直待到比賽結束,所以說,一般情況下,自動使用較多,只有非常重要的變量才需要靜態。
    作用域分爲代碼塊作用域、函數原型作用域、文件作用域與函數作用域,有些類似足球場地,整個足球場就是文件作用域,作爲全局變量的運動員擁有文件作用域,可以全場飛奔。將足球場地劃分成後場,中場和前場幾個區域,區域對應文件中的代碼塊,就像後衛一般在後場活動一樣,代碼塊作用域的變量只能在代碼塊中生效。
    函數原型作用域(function prototype scope)翻譯的讓人很不容易理解,要說清楚函數原型作用域,需要先理解函數原型。函數原型(function prototype)實際上就是函數接口(function interface),聲明瞭函數的返回類型、名稱、參數類型和參數數量。將函數原型作爲函數的聲明,放在頭文件中,預處理可以使程序拆分成編譯單元,編譯器將編譯單元分別編譯彙編成object文件,再由鏈接器組合成可執行文件或者庫。關於函數原型作用域,我個人簡單粗暴的理解是:函數原型中的參數具有函數原型作用域。以下面示例爲例,函數原型中標識符“ lho”的範圍始於逗號,結束於右括號。

#include <stdio.h>
 
/* 函數原型 */
int simple_add (int lho, int rho);
 
int lho;  /* 與函數原型中的 "lho" 不衝突 */
 
int main(void)
{
    printf("%d\n", simple_add(1,2));
 
    return 0;
}
 
int simple_add (int lho, int rho)
{
    return (lho+rho);
}

    寫了半天,函數原型作用域然並卵?額,你看那個人,他好像一條狗啊。
    鏈接是從空間的角度定義的,用於引用變量或函數。鏈接分爲內鏈接、外鏈接和空鏈接。外鏈接和內鏈接比較好理解,它們的相同之處是都擁有文件作用域,定義變量或函數之後可以在本文件內任何地方進行引用;不同之處在於,外鏈接表示可以在其他文件中引用本文件的變量或函數,而內鏈接性質的變量或函數不能被其他文件引用。空鏈接表示不能被引用,代碼塊作用域的鏈接全是空鏈接,這其中“自動”和“寄存器”存儲類比較好理解,因爲調用完代碼塊,內存空間就釋放了,數據不能保存下來也就談不上引用了。具有代碼塊作用域的靜態稍微有點複雜,用打車和開車形容比較合適。靜態就是開自己的車,雖然平時車就停着不動(靜態變量一旦創建,即使代碼塊調用結束也不會消失,會持續到程序結束),但別人不能開走(無法引用具有代碼塊作用域的靜態變量,無法在其他文件中引用靜態函數),需要的時候只有本人能啓動(只有引用同一代碼塊才能使用靜態變量,只有在本地文件中引用靜態函數),而相對的,“自動”和“寄存器”就是打出租車了,因爲本來就沒有車,所以不可能把車借給別人。具有代碼塊作用域的靜態變量示例如下:

#include<stdio.h>
void trystat(void);

int main(void)
{
    int count;

    for(count = 1;count <= 3;count++)
    {
        printf("Here comes iteration %d: \n", count);
        trystat();
    }
    
    return 0;
}

void trystat(void)
{
    int fade = 1;
    static int stay = 1;

    printf("fade = %d and stay = %d\n",fade++, stay++);
}

    這裏的變量stay只有使用trystat函數才能調用,如果想在其他函數中使用,只有把它的作用域從代碼塊改爲文件,即,把它改爲全局變量:

#include<stdio.h>
void trystat(void);
void printstay(void);

static int stay = 1;
int main(void)
{
    int count;

    for(count = 1;count <= 3;count++)
    {
        printf("Here comes iteration %d: \n", count);
        trystat();
    }
    printstay();
    return 0;
}

void trystat(void)
{
    int fade = 1;

    printf("fade = %d and stay = %d\n",fade++, stay++);
}

void printstay(void)
{
    printf("This is function printstay, stay=%d\n",stay);
}

參考文檔

[1]wikipedia.Function prototype[EB/OL].https://en.wikipedia.org/wiki/Function_prototype,2020-04-29.
[2]polytechnique.function_prototype_scope[EB/OL].http://www.enseignement.polytechnique.fr/informatique/INF478/docs/Cpp/en/c/language/function_prototype_scope.html,2020-01-01.
[3]Stephen Prata.C Primer Plus[M].人民郵電出版社:北京,2014:321-335.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章