C語言 變數的儲存類

更新於 發佈於 閱讀時間約 13 分鐘

● auto(自動)
● register(暫存器)
● static(靜態)
● extern(外部)

定義

作用範圍(scope)、儲存時期(life time)連結(linkage)的不同作為區別。


●作用範圍:分為區域變數(只能作用於其函數內)全域變數(作用於不同文件中)

接著我們來看看以下兩種程式碼哪個是可執行的。

#include "stdio.h"

void text(){
  printf("%d\n",a);
}

int main(void){
  int a = 0;
  text();
}

--------------------------------結果---------------------------------
’a’ was not declared in this scope

沒錯,這段程式碼是無法執行的,它會跑出一條’a’ was not declared in this scope的訊息,也就是a變數不存在於該區塊中。為什麼呢?我們可以發現,a的定義是在main這個主函數裡面,它是無法作用在其他函數內的,相反的我們在也可以發現,a也只會作用在main裡面,這就是所謂的區域變數。

#include "stdio.h"

int a = 1;

int main(void){
  printf("%d\n",a);
}

--------------------------------結果---------------------------------
1

而這段程式碼中,a是定義在任何函數外,就結果來說,我們可以正常看到它輸出了1。因此a的定義為全域變數,也就是在它定義開始一直到文件的最後一行,任何函式都可以使用a這個變數。

那如果,同時使用呢?

#include "stdio.h"

int a = 1;

int main(void){
  int a = 2;
  printf("%d\n",a);
}

--------------------------------結果---------------------------------
2

結果很明顯,輸出的會是2。由這點可知,局部變數在該函數中,作用的優先會大於全局變數,因此main函式中,a的變數會對應到函數內部,定義為2的a。


●存儲時期(life time):分為靜態存儲(直到整個程式結束前,該變數的值會持續保留,不受二次定義賦值影響)以及自動存儲(一旦該函式結束後,其變數就會消失)兩種。

一樣來看看這兩種的差別吧!

#include "stdio.h"

void text(){
  int a = 0;
  a++;
  printf("%d\n",a);
}

int main(void){
  text();
  text();
  text();
}

--------------------------------結果---------------------------------
1
1
1

結果輸出了不同行的三個1,這是為什麼呢?當main函數跑第一個text()的時候,text內部會創建一個a,並賦值0給a。接著第六行會讓a的值再加上1,也就是0+1=1。最後輸出a的值,並結束這個函數,同時刪掉a這個變數,注意喔!當函數結束後,裡面所有的變數都是會刪除的。因此,我們可以理解到,main使用text函式的三次中,a都會初始定義並賦值為0,所以這也是為什麼輸出的結果都是相同的,而這就是所謂的自動存儲

#include "stdio.h"

void text(){
  static int a = 0;
  a++;
  printf("%d\n",a);
}

int main(void){
  text();
  text();
  text();
}

--------------------------------結果---------------------------------
1
2
3

而這一次的執行可以得到不同行的1、2、3,為什麼加上static之後,就會這樣呢?當main在跑text第一次的時候,流程都跟前面講左方程式碼時一樣,但在最後輸出a的值之後,結束函數的同時並不會刪除掉a的值。並且在第二次跑text函數時,第五行不會重新賦值0給a,a變數仍舊保持著上一次結果的值,也就是1。因此在這次的text中,它會再次加1並輸出。最後我們可以理解到,函數在結束後,不會刪除掉有static描述的變數,並保持其值,而這就是所謂的靜態存儲


●連結(linkage):分為空連結(只能於函數內使用,區域變數)內部連結(可於定義並賦值位置一直到文件最後一行都可使用,類似全域變數)以及外部連結(可跨文件做使用)

讓我們測驗看看外部連結吧~

(text.c)
int b = 10;

(main.c)
#include "stdio.h"

int main(void){
  extern int b;
  printf("%d",b);
}

--------------------------------結果---------------------------------
10

當我在text.c檔案中定義一個變數b,只要在另外一個文件main.c當中,在定義類型前面再加一個extern修飾,就能跨文件使用變數了。在main.c執行後,即可成功輸出10。而這種方法,就是所謂的外部連結。

但要特別注意的是,外部連結必須是在同個資料夾,否則無法透過外部連結使用喔。


儲存類

●auto(自動)



auto擁有自動存儲區域變數空連結的特性,簡單來說就是auto只能修飾在函數內的變數,只能在函數內使用,且函數執行結束後就會消失。事實上,任何在函數內定義的變數,只要沒有特別修飾,直接定義類型、名稱及值後,就會自動修飾為auto。簡單來說就是auto在修飾上面,其實沒有特別用處。

#include "stdio.h"

int main(void){
  auto int b = 0;
  printf("%d",b);
}

--------------------------------結果---------------------------------
0

另外auto還有一個作用是,自動定義變數的類型,如下。

#include "stdio.h"

int main(void){
  auto b = 0;
  printf("%d",b);
}

--------------------------------結果---------------------------------
0

如果使用auto當定義類型時,它會自動幫b搜尋它適合的類型,也就是int。但如果沒有特別指定值的時候,變數則會默認為int。


●register(暫存器)

register擁有自動存儲區域變數空連結的特性,一樣是只能修飾在函數內的變數,它的特點在於,經過register修飾的變數,會存放在暫存器當中,而不是平常的記憶體內。因此它的執行速度會大幅提升,如下圖採用CR Ferreira的時間計算程式碼,計算有無register修飾的時間差。

#include "stdio.h"
#include "sys/time.h"

int main(void){
  double sum = 0;
  double add = 1;
  struct timeval begin, end;

  gettimeofday(&begin, 0);
  register int a,i;//暫存器變數

  for (i=0; i<1000000000; i++){//主要執行內容
    a++;
  }

  gettimeofday(&end, 0);
  long seconds = end.tv_sec - begin.tv_sec;
  long microseconds = end.tv_usec - begin.tv_usec;
  double elapsed = seconds + microseconds*1e-6;
  printf("Time measured: %.3f seconds.\n", elapsed);
  return 0;
}

--------------------------------結果---------------------------------
Time measured: 0.681 seconds.

-------------------------------分隔線--------------------------------
#include "stdio.h"
#include "sys/time.h"

int main(void){
  double sum = 0;
  double add = 1;
  struct timeval begin, end;

  gettimeofday(&begin, 0);
  int a,i;//一般變數

  for (i=0; i<1000000000; i++){//主要執行內容
  a++;
  }

  gettimeofday(&end, 0);
  long seconds = end.tv_sec - begin.tv_sec;
  long microseconds = end.tv_usec - begin.tv_usec;
  double elapsed = seconds + microseconds*1e-6;
  printf("Time measured: %.3f seconds.\n", elapsed);
  return 0;
}

--------------------------------結果---------------------------------
Time measured: 2.215 seconds.

可以清楚看出,有register修飾的文件,執行速度大幅領先無修飾的文件。


●static(靜態)

static擁有靜態區域變數、靜態全域變數兩種方式。前者只能在函數內修飾,並擁有靜態存儲、區域變數、空連結的特性後者只能在函數外修飾,擁有靜態存儲、全域變數、內部連結的特性

#include "stdio.h"
static int i;//靜態全域變數

void text(){
  static int j;//靜態區域變數
}

靜態區域變數的特性,在前面有說過,能夠在整個程式執行結束前,一直保有其值不會消失。這時候你可能會想,全域變數本來就是到程式執行結束才會消失,那還有必要寫static來修飾嗎?

確實,是如此沒錯,但全域變數跟靜態全域變數的最大差別在於連結性。一般沒做修飾的全域變數是可以跨文件利用extern做連結的,但經過static修飾的變數,則是無法跨文件取得,也就是內部連結,僅供該文件使用。

(text.c)
static int i = 5;

(main.c)
#include "stdio.h"

extern int i;

int main(void){
  printf("%d",i);
}

--------------------------------結果---------------------------------

當在main.c執行後,就無法取得i這個變數,也因此無法取得i的值,這就是static的內部連結性質。


● extern(外部)

一般在函數外未特別修飾的變數,擁有靜態存儲、全域變數、外部連結的特性,而extern則可以引用這些變數。相關實作在前方有示範過了,這邊就不多加掩飾。

參考內容

C 存儲類 w3big.com

C語言 存儲類說明符 wfreehorse











留言
avatar-img
留言分享你的想法!
avatar-img
咖啡因學習教室
12會員
18內容數
這裡是來自 高科大 資管系二年級的學生,希望能在學習的過程中,也分享這些知識給大家。
咖啡因學習教室的其他內容
2024/03/14
前言 那麼今天要來教大家,如何實現各種排版,以及不同的 CSS 可以做出怎樣的效果。 整理好你的思緒,深深吸一口氣,讓我們在 2024 這嶄新的一年當中,開始新的學習之旅吧。 字體相關 color 設定文字的顏色。 <p style="color: blue;">這是藍色文字。</
2024/03/14
前言 那麼今天要來教大家,如何實現各種排版,以及不同的 CSS 可以做出怎樣的效果。 整理好你的思緒,深深吸一口氣,讓我們在 2024 這嶄新的一年當中,開始新的學習之旅吧。 字體相關 color 設定文字的顏色。 <p style="color: blue;">這是藍色文字。</
2024/03/14
前言 今天課程要來學習,在 .css 設計樣式後,怎麼透過選擇器,讓 .html 可以有所配對,經過這一步後,便可以開始學習,如何正式設計 .css 了。 選擇器 介紹 還記得上次課程,我們在 .css 檔案中,撰寫的程式碼嗎?讓我們來複習看看: .highlight { co
2024/03/14
前言 今天課程要來學習,在 .css 設計樣式後,怎麼透過選擇器,讓 .html 可以有所配對,經過這一步後,便可以開始學習,如何正式設計 .css 了。 選擇器 介紹 還記得上次課程,我們在 .css 檔案中,撰寫的程式碼嗎?讓我們來複習看看: .highlight { co
2024/03/14
前言 終於要到這個振奮人心的章節了,我們終於要來學習,如何讓自己的網頁更加美觀。 但在這之前,我們肯定得先學習,如何將我們的 CSS 檔案,連接到 HTML 當中。 連結分類 首先,我們在連結 CSS 的方法中,有分為三種: 內聯連結 在 .html 當中,任一標籤的裡面,用屬性 s
2024/03/14
前言 終於要到這個振奮人心的章節了,我們終於要來學習,如何讓自己的網頁更加美觀。 但在這之前,我們肯定得先學習,如何將我們的 CSS 檔案,連接到 HTML 當中。 連結分類 首先,我們在連結 CSS 的方法中,有分為三種: 內聯連結 在 .html 當中,任一標籤的裡面,用屬性 s
看更多
你可能也想看
Thumbnail
孩子寫功課時瞇眼?小心近視!這款喜光全光譜TIONE⁺光健康智慧檯燈,獲眼科院長推薦,網路好評不斷!全光譜LED、180cm大照明範圍、5段亮度及色溫調整、350度萬向旋轉,讓孩子學習更舒適、保護眼睛!
Thumbnail
孩子寫功課時瞇眼?小心近視!這款喜光全光譜TIONE⁺光健康智慧檯燈,獲眼科院長推薦,網路好評不斷!全光譜LED、180cm大照明範圍、5段亮度及色溫調整、350度萬向旋轉,讓孩子學習更舒適、保護眼睛!
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
一、存取修飾詞public / private / protected / internal 二、參數修飾詞ref / in / out >>>>>由於我們在寫程式時,會去宣告一些變數、常數相關識別詞,並且在class(類別)中會寫一些事情或動作讓程式去運行,然而這個概念就是去定義對於我們所寫的內容
Thumbnail
一、存取修飾詞public / private / protected / internal 二、參數修飾詞ref / in / out >>>>>由於我們在寫程式時,會去宣告一些變數、常數相關識別詞,並且在class(類別)中會寫一些事情或動作讓程式去運行,然而這個概念就是去定義對於我們所寫的內容
Thumbnail
在JS中很重要的觀念就是hoisting,中文叫做「提升」
Thumbnail
在JS中很重要的觀念就是hoisting,中文叫做「提升」
Thumbnail
這篇文章將會講述 static 的小技巧,讓常用的欄位不用重複指定或拖拉。
Thumbnail
這篇文章將會講述 static 的小技巧,讓常用的欄位不用重複指定或拖拉。
Thumbnail
這一篇文章將會從Microsoft的.NET Class Library開始介紹,在介紹具狀態和不具狀態,以及物件和new關鍵字。
Thumbnail
這一篇文章將會從Microsoft的.NET Class Library開始介紹,在介紹具狀態和不具狀態,以及物件和new關鍵字。
Thumbnail
本篇文章將會介紹C#的基礎構成和字串的使用,若想要更詳細的教學,可以參考前一篇文章,前往Microsoft官方教學學習。
Thumbnail
本篇文章將會介紹C#的基礎構成和字串的使用,若想要更詳細的教學,可以參考前一篇文章,前往Microsoft官方教學學習。
Thumbnail
auto(自動)、register(暫存器)、static(靜態)、extern(外部),以作用範圍(scope)、存儲時期(life time)、連結(linkage)的不同作為區別。
Thumbnail
auto(自動)、register(暫存器)、static(靜態)、extern(外部),以作用範圍(scope)、存儲時期(life time)、連結(linkage)的不同作為區別。
Thumbnail
撰寫程式時,有沒有想過宣告的這些變數是怎麼運作的呢? 本文介紹了Value Type跟Reference Type,以及Variable的基本命名方式。
Thumbnail
撰寫程式時,有沒有想過宣告的這些變數是怎麼運作的呢? 本文介紹了Value Type跟Reference Type,以及Variable的基本命名方式。
Thumbnail
使用者自訂的資料型別
Thumbnail
使用者自訂的資料型別
Thumbnail
int main()、註解//、include 、命名空間、using namespace
Thumbnail
int main()、註解//、include 、命名空間、using namespace
Thumbnail
今天來到Day5了,也來到基礎教學的最後一部分,今天要講解的就是函式(function),有分成內建函數,以及自訂函數,再來是import模組,也就是導入py檔,除了可以導入自行撰寫的py檔,網路上也有許多大神分享相當方便使用的py檔,最後再講解一下如何進行異常處理,也就是Debug的部分
Thumbnail
今天來到Day5了,也來到基礎教學的最後一部分,今天要講解的就是函式(function),有分成內建函數,以及自訂函數,再來是import模組,也就是導入py檔,除了可以導入自行撰寫的py檔,網路上也有許多大神分享相當方便使用的py檔,最後再講解一下如何進行異常處理,也就是Debug的部分
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News