<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
大家好,歡迎來到C語言深度解析專欄—關鍵字詳解第二篇,在本篇中我們將會對static關鍵字進行詳細介紹,其中要求我們掌握我上一篇中所講到的全域性變數、區域性變數、作用域以及生命週期的相關概念,如果對這幾個概念比較模糊的同學可以先移步我上一篇部落格,下面是部落格連結。
C語言關鍵字詳解
為了理解static修飾函數的作用,我們需要了解多檔案的相關內容
這裡我先介紹一下標頭檔案的建立:標頭檔案的建立與.c檔案的建立十分相似,僅僅是在選擇的時候把c++檔案改成.h而已
.h:我們稱之為標頭檔案,一般包含函數宣告,變數宣告,宏定義,標頭檔案等內容(header)
.c: 我們稱之為原始檔,一般包含函數實現,變數定義等 (.c:c語言)
多檔案就是在一個.h檔案下,包含多個.c檔案,比如main.c test1.c test2.c teset3.c … …
在一個公司的大型專案中,預期產品所要實現的功能往往是十分複雜的,所以一般都會將功能進行模組化處理,從而便於我們進行程式碼的複用、程式碼的修改與維護以及多人共同作業,自然我們一個程式中就需要多個.c檔案
單純的使用原始檔,組織專案結構的時候,專案越大越複雜維護成本會變得越來越高!
所以我們在組織專案結構的時候會使用標頭檔案來減少大型專案的維護成本問題。
補充:標頭檔案中 #pragma once 的含義
大家在建立一個.h 標頭檔案的時候會發現編譯器在標頭檔案的開頭會自動加上 #pragma once
相信有許多小夥伴在曾今或者現在都對這東西有著深深的疑惑,其實它是用來防止標頭檔案被反覆包含的,舉個栗子
如上所示:我在test.h中包含了標頭檔案<stdio.h>,但是在main.c中我又同時包含了test.h 和 stdio.h ,這就造成了stdio.h被包含了兩次,使得程式在編譯的時候將stdio.h 裡面的內容拷貝了兩份,造成程式碼冗餘,而#pragma once 會檢查該標頭檔案是否已經被包含,如若是就不在進行拷貝。
防止標頭檔案反覆包含的另一種方法(涉及預處理內容,暫時不講,同學們當作瞭解即可)
在上圖中我們在test.c 檔案中中定義了一個全域性變數和一個函數,然後在test.h檔案中對其進行宣告,最後在main.c檔案中對全域性變數和函數進行列印和呼叫,我們可以發現,這種做法是可行的,也就是說:全域性變數和函數可以跨檔案存取的(這個結論在解釋下文static作用時會被用到)
static 整體闡述
上圖是MSDN對static的解釋,翻譯過來就是:修改變數時,static關鍵字指定該變數具有靜態持續時間(在程式開始時分配,在程式結束時釋放),並將其初始化為0,除非指定了其他值。在檔案範圍中修改變數或函數時,static關鍵字指定該變數或函數具有內部連結(其名稱在宣告它的檔案外部不可見)。這段話讀起來沒什麼具體的概念,接下來我從static 作用的三個物件來帶大傢俱體瞭解static。
圖一:test 函數裡面定義的 a 是區域性變數,區域性變數在棧區上開闢空間,棧區的使用特點是進入變數的生命週期時自動為其開闢空間,離開變數的生命週期時自動銷燬對應空間,所以這裡每次呼叫 test 函數時 a 都會被重新定義並初始化為0,所以螢幕上列印的是10個1;
圖二:我們把 a 用 static 修飾後發現螢幕列印的是1到10,就好像每次呼叫完 test 函數後 a 並沒有被銷燬,而是繼續使用,下次呼叫 test 函數時 a 直接在之前的基礎上進行 ++ 操作。
所以 static 修飾區域性變數的作用是:改變區域性變數的生命週期,本質上是改變了區域性變數的儲存位置,讓區域性變數不再是在棧區上開闢空間,而是直接在靜態區上開闢空間,從而使得區域性變數擁有和全域性變數一樣的生命週期,即隨著整個程式生成和銷燬。
更深入的理解 static 修飾區域性變數的作用:圖三,我們的程式從原始檔(.c檔案)變成可執行程式(.exe檔案)需要經過編譯連結執行三個環節,而編譯環節又分為預處理、編譯、組合三個階段,在組合階段,編譯器會把我們的C語言程式碼轉換成組合程式碼,而每一條C語言語句都對應著多句組合程式碼,然而在圖三中,我們可以觀察到,只有 static int a = 0; 這條語句沒有對應的組合程式碼,也就是說,C語言在編譯的時候會直接跳過這條語句。
本質上是:在編譯環節的編譯階段編譯器就會為被 static 修飾的區域性變數分配空間,所以C程式在執行的過程中會直接跳過 static 修飾的語句,也就是說,在第二次及以上甚至第一次呼叫 test 函數時 static int a = 0; 這條語句都不會被執行。
補充:記憶體分佈:
要弄清楚這個問題,我們首先得知道記憶體佈局是怎樣的:
如圖,左邊是記憶體的具體劃分,右邊是記憶體的大概劃分,在C語言階段我們只需要記住右邊的圖就可以了,從圖中我們可以看到,區域性變數的記憶體開闢是在棧區上的,而棧區的特點是進入程式碼塊開闢空間,離開程式碼塊釋放空間,所以區域性變數的作用域和生命週期只在程式碼塊內,而用static的變數則直接在靜態區開闢空間,所以變數的生命週期得到延長。
圖一圖二對比分析:我在Add.c中定義了一個全域性變數g_val,因為全域性變數具有外部連結屬性,所以我只需要在test.c中對g_val進行宣告之後就可以正常使用了,但是當我用 static 來修飾g_val時,我們發現,編譯器說g_val是無法解析的外部符號;
所以 static 修飾全域性變數的作用是:改變了全域性變數的外部連結屬性(可以在其他原始檔內被存取),使其變成內部連線屬性(只能在本檔案內部被存取),給我們的感覺是全域性變數的作用域變小了。
圖一圖二對比分析:這裡和 static 修飾全域性變數非常類似,我在Add.c中定義了一個Add函數,因為函數也具有外部連結屬性,所以我只需要在test.c中對Add函數進行宣告之後就可以正常使用了,但是當我用 static 來修飾Add函數時,我們發現,編譯器說Add是無法解析的外部符號;
所以 static 修飾函數的作用是:改變了函數的外部連結屬性(可以在其他原始檔內被存取),使其變成內部連線屬性(只能在本檔案內部被存取),給我們的感覺是函數的作用域變小了。
到此這篇關於全面瞭解C語言 static 關鍵字的文章就介紹到這了,更多相關C語言 static 關鍵內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45