[C]static修飾

更新於 2024/07/22閱讀時間約 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至少有兩個明顯的好處:

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


如果是失業的時候寫的 -那就是隨筆 如果是工作的時候寫的 -那就是筆記 但我狀態切換的很頻繁 那目前這坨東西就定義成「隨筆記」好了
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
👋 剛學OpenGL時就對這件事情感到相當疑惑,還沒開始寫程式,光是前置作業,就被各種函式庫搞得頭痛,為什麼不能像OpenCV一樣方便呢?後來才知道這跟OpenGL的本質有關;怕自己忘記故在此紀錄之。
👋 剛學OpenGL時就對這件事情感到相當疑惑,還沒開始寫程式,光是前置作業,就被各種函式庫搞得頭痛,為什麼不能像OpenCV一樣方便呢?後來才知道這跟OpenGL的本質有關;怕自己忘記故在此紀錄之。
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
照夜白/圖 貓落/文 一場廢盡千辛萬苦的圖文集 --《漠視錄》 《C.A.G.E》 別看了 是嗎.. 像是牢籠嗎? 如何向內擁抱都有個極限 最後會停在 自身 一個 單位 太多了已經
C 台灣的新創團隊 如果想要使用以太坊技術 來營利同時做公益慈善 可以發展那些專案 #VitalikButerin #ETHTaipei2024 #ETHTaipeiHackathon2024 ... (好的顧問導師教練 協助妳提早得到幸福 更快實現夢想 幸福課程
C如何找到和確認誰是真正該被幫助的善良弱勢? 如何找到和確認真正在做對的事的公益慈善? 如何查核公益慈善的正職和志工 避免有用善心的人做的很累 混水摸魚的卻可以領到薪水拿到時數證明? 幸福教練黃老師 潮資訊媒體 找到和確認真正需要幫助的善良弱勢 以及評估公益慈善的正確性和透明
Thumbnail
c女生在高中 高職 大學 如果想參加各種科技新創 社會創新 永續設計等等相關比賽 應該主動學習和培養 哪些知識和技能 幸福教練黃老師 潮資訊媒體 參加科技新創、社會創新以及永續設計等相關比賽, 女生在高中或高職階段 可以主動學習和培養以下知識和技能: 程式設計和編程
Thumbnail
C型肝炎是由C型肝炎病毒感染引起的疾病,常見症狀包括疲倦、食慾不振、噁心、腹部不適等。文章介紹了C型肝炎的傳染方式、感染風險族群以及預防方法。此外,也提供了西醫和中醫對C型肝炎的治療方法和常用中藥的介紹。
Thumbnail
當我的自營工作室客源開始穩定時,C就這樣悄悄走進我的生命裡,至今為止,我和C從來沒有吵架過,連一點點的不愉快、疙瘩甚至懷疑都沒有,對我而言,C的意義只有美好。她總是希望我過得好,我也祝福她永遠快樂。     我的租屋處是一棟由五樓透天隔間的大套房,而我就住在頂樓,旁邊還有一間空房一直沒人承租
Thumbnail
發洩完情緒之後,內心裡,總會有一種抒坦。是那種放下的感覺,是那種,什麼都好,都可以不重要,只有自己的那種,唯我獨尊的快感。可以不必再在意些什麼,不必再掙扎著去要求些什麼。唯有放寛心了,才能更真實去體驗自己正在經歷的過程。放下些什麼,才能獲得些什麼。 昨晚,C因為工作無法前來陪伴休假的我。經前症候群嚴
Thumbnail
這篇文章將會講述 static 的小技巧,讓常用的欄位不用重複指定或拖拉。
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
照夜白/圖 貓落/文 一場廢盡千辛萬苦的圖文集 --《漠視錄》 《C.A.G.E》 別看了 是嗎.. 像是牢籠嗎? 如何向內擁抱都有個極限 最後會停在 自身 一個 單位 太多了已經
C 台灣的新創團隊 如果想要使用以太坊技術 來營利同時做公益慈善 可以發展那些專案 #VitalikButerin #ETHTaipei2024 #ETHTaipeiHackathon2024 ... (好的顧問導師教練 協助妳提早得到幸福 更快實現夢想 幸福課程
C如何找到和確認誰是真正該被幫助的善良弱勢? 如何找到和確認真正在做對的事的公益慈善? 如何查核公益慈善的正職和志工 避免有用善心的人做的很累 混水摸魚的卻可以領到薪水拿到時數證明? 幸福教練黃老師 潮資訊媒體 找到和確認真正需要幫助的善良弱勢 以及評估公益慈善的正確性和透明
Thumbnail
c女生在高中 高職 大學 如果想參加各種科技新創 社會創新 永續設計等等相關比賽 應該主動學習和培養 哪些知識和技能 幸福教練黃老師 潮資訊媒體 參加科技新創、社會創新以及永續設計等相關比賽, 女生在高中或高職階段 可以主動學習和培養以下知識和技能: 程式設計和編程
Thumbnail
C型肝炎是由C型肝炎病毒感染引起的疾病,常見症狀包括疲倦、食慾不振、噁心、腹部不適等。文章介紹了C型肝炎的傳染方式、感染風險族群以及預防方法。此外,也提供了西醫和中醫對C型肝炎的治療方法和常用中藥的介紹。
Thumbnail
當我的自營工作室客源開始穩定時,C就這樣悄悄走進我的生命裡,至今為止,我和C從來沒有吵架過,連一點點的不愉快、疙瘩甚至懷疑都沒有,對我而言,C的意義只有美好。她總是希望我過得好,我也祝福她永遠快樂。     我的租屋處是一棟由五樓透天隔間的大套房,而我就住在頂樓,旁邊還有一間空房一直沒人承租
Thumbnail
發洩完情緒之後,內心裡,總會有一種抒坦。是那種放下的感覺,是那種,什麼都好,都可以不重要,只有自己的那種,唯我獨尊的快感。可以不必再在意些什麼,不必再掙扎著去要求些什麼。唯有放寛心了,才能更真實去體驗自己正在經歷的過程。放下些什麼,才能獲得些什麼。 昨晚,C因為工作無法前來陪伴休假的我。經前症候群嚴
Thumbnail
這篇文章將會講述 static 的小技巧,讓常用的欄位不用重複指定或拖拉。