[C]static修飾

更新 發佈閱讀 8 分鐘


拜託,注意一下變數的作用域,都出來工作了,別像國中生寫程式一樣


1.修飾局部變數


先看如果沒有使用static修飾時的情況

給定一程式

#include <stdio.h>
#include <stdlib.h>

void func(void)
{
int x = 0 ;

x = x + 1 ;

printf("%p -> %d \\n", &x , x );
}
int main()
{
func();
func();
func();
exit(0);
}

執行結果:

0x7ffc766476c4 -> 1
0x7ffc766476c4 -> 1
0x7ffc766476c4 -> 1

可以看到重複執行func()輸出結果都是1

因為每次的func( )中的int x = 0 皆會重複將x定義為0

之後再+1

另外雖然印出來的地址相同且變數相同

x變數實際上每次都會在函式結束時銷毀,下次執行時再被定義

所以實際上三個是不同的變數

若用古老一點的gcc版本,每次印出來就是三組不同的記憶體位址了

若將func()中的i使用static修飾:

void func(void)
{
static int x = 0 ;

x = x + 1 ;

printf("%p -> %d \\n", &x , x );
}

執行結果:

0x55ed3fc40014 -> 1
0x55ed3fc40014 -> 2
0x55ed3fc40014 -> 3

可以發現static int x = 0 ; 僅僅被定義了一次

後續重複執行func時則會根據x的初始值進行累加

此時無論你使用何種gcc的版本,記憶體位址印出來的絕對會是同一塊地址

這裡可以簡單理解為:static修飾的變量具繼承性,且在文件中只被定義一次



2.修飾全局變數


在一些稍具規模的專案中最常使用的情況

給定三個檔案文件,主文件main.c 以及定義函式的func.c , func.h

func.c :

#include <stdio.h>
#include <stdlib.h>

#include "func.h"

static int i = 100;

void func (void)
{

printf("[%s] : i = %d\\n" , __FUNCTION__ , i);

exit(0);
}
/* 實現func() 作用為印出i值 */

func.h :

#ifndef FUNC_H___
#define FUNC_H___

void func(void);/* 定義func() */

#endif

main.c :

#include <stdio.h>
#include <stdlib.h>

#include "func.h"

static int i = 10 ;

int main()
{
printf("[%s] : i = %d\\n" , __FUNCTION__ , i);/* 印出i值 */

func();/* 呼叫func() */

exit(0);
}

其中__FUNCTION__ 為gcc預定義的巨集,可以輸出當前函式名稱

輸出結果:

[main] : i = 10
[func] : i = 100

可以看到透過static,使兩個文件的變數i分別獨立,生命週期僅涵蓋當前文件

main函數中的printf印出的當前文件的i=10

而之後使用的func()則是使用func.c中定義的i=100




3.全局變數-沒有static的話?


接著剛剛的程式碼

假設將func.c以及main.c中的i的前方static拿掉

在進行編譯時,會顯示下列錯誤訊息:

/usr/bin/ld: /tmp/ccjtT5QF.o:(.data+0x0): multiple definition of `i'; 
/tmp/cc2KBh7e.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status

看到了訊息中的multiple definition of `i',表示我們對i的定義重複且發生衝突了

使用static修飾即是防止對象向外擴展,而造成這種編譯錯誤

因此在大型專案的整合上,變數的作用域要小心且嚴謹的檢查


「欸欸欸我跑自己的程式就編譯成功,怎麼跟你們的合一起就不行?你們寫錯了吧?」 by 三周後被資遣雷包工程師-(真人真事🙃)


4.用static修飾函數與簡單封裝


static 亦可以用於修飾函數

不更改main.c

func.c以及func.h中將func()static修飾-

func.c :

#include <stdio.h>
#include <stdlib.h>

#include "func.h"

static int i = 100;

static void func (void)
{

printf("[%s] : i = %d\\n" , __FUNCTION__ , i);

exit(0);
}
/* 實現func() 作用為印出i值 */

func.h :

#ifndef FUNC_H___
#define FUNC_H___

static void func(void);/* 定義func() */

#endif

此時func()已經被staic修飾而無法被main.c使用

因此編譯時gcc會跳出以下訊息:

func.h:4:13: warning: ‘func’ used but never defined
4 | static void func(void);
| ^~~~
/usr/bin/ld: /tmp/ccqYGJSq.o:(.data+0x0): multiple definition of `i'; /tmp/cchlq9eW.o:(.data+0x0): first defined here
/usr/bin/ld: /tmp/cchlq9eW.o: in function `main':
main.c:(.text+0x2f): undefined reference to `func'
collect2: error: ld returned 1 exit status

其中顯示了main.c無法引用到func()

func()static修飾後僅在func.cfunc.h 定義

因此static 的修飾防止了func()的定義外擴

如何使main.c使用func()的功能呢?

由於此時我們使用static 修飾func()來防止外擴

因此我們另外創建一個call_func()來提供main.c使用:

func.c :

#include <stdio.h>
#include <stdlib.h>

#include "func.h"

static int i = 100;

static void func (void)
{

printf("[%s] : i = %d\\n" , __FUNCTION__ , i);

exit(0);
}
/* 實現func() 作用為印出i值 */

void call_func(void)
{
func();
}
/* 實現call_func() 作用為執行func() */

func.h :

#ifndef FUNC_H___
#define FUNC_H___

static void func(void);/* 定義func() */
void call_func(void);/* 定義call_func() */
#endif

main.c :

#include <stdio.h>
#include <stdlib.h>

#include "func.h"

static int i = 10 ;

int main()
{
printf("[%s] : i = %d\\n" , __FUNCTION__ , i);/* 印出i值 */

call_func();/* 執行call_func() */

exit(0);
}

執行結果:

[main] : i = 10
[func] : i = 100

如此可以保證函式定義不外擴的同時

使外部的main.c使用func()的功能

透過修飾可以在C語言中對函式進行簡單的封裝




5.後記


在此只整理c語言的用法

在c++的環境static更可以用來修飾class內的成員

而善用static至少有兩個明顯的好處:

  • 避免全域變數在其他文件中可見,減少衝突跟不必要的依賴
  • 減少了不必要的初始化


留言
avatar-img
typedef struct 隨筆記{
1會員
6內容數
如果是失業的時候寫的 -那就是隨筆 如果是工作的時候寫的 -那就是筆記 但我狀態切換的很頻繁 那目前這坨東西就定義成「隨筆記」好了
2024/09/22
探討指向函數的指標 這種用法在稍具規模的專案中常看到 但自己實作時很少用到 但偏偏有時面試會問Orz
Thumbnail
2024/09/22
探討指向函數的指標 這種用法在稍具規模的專案中常看到 但自己實作時很少用到 但偏偏有時面試會問Orz
Thumbnail
2024/09/12
簡單紀錄二維陣列的配置方式及取址差異
Thumbnail
2024/09/12
簡單紀錄二維陣列的配置方式及取址差異
Thumbnail
2024/09/10
找工作面試常常問這個 就簡單紀錄一下
Thumbnail
2024/09/10
找工作面試常常問這個 就簡單紀錄一下
Thumbnail
看更多
你可能也想看
Thumbnail
高中數學主題練習—根式化簡
Thumbnail
高中數學主題練習—根式化簡
Thumbnail
高中數學主題練習—根式化簡
Thumbnail
高中數學主題練習—根式化簡
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
高中數學主題練習—對數方程式
Thumbnail
高中數學主題練習—對數方程式
Thumbnail
高中數學主題練習—標準化計算
Thumbnail
高中數學主題練習—標準化計算
Thumbnail
就簡單介紹一下static
Thumbnail
就簡單介紹一下static
Thumbnail
中學數學基礎練習—一元二次方程式
Thumbnail
中學數學基礎練習—一元二次方程式
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News