模塊化設計,static和extern(面試題常見)

文章目錄

  • 一、函數的聲明和定義
    • 1.1 單個文件
    • 1.2 多個文件
    • 1.3 static和extern
      • 1.3.1 static修飾局部變量
      • 1.3.2 static修飾全局變量
      • 1.3.3 static修飾函數
  • 總結


一、函數的聲明和定義

1.1 單個文件

一般我們在使用函數的時候,直接將函數寫出來就使用了

題目:寫一個函數判斷一年是否是閏年

在這里插入圖片描述
圖中4-10行是函數的定義,16行這里是函數的調用,在這種場景下,函數的定義在函數的調用之前,沒啥問題。

而在另一個場景下,當我們需要把函數的定義放在函數的調用后邊,因為編譯器是從前mian的函數往后處理代碼的,當調用函數的時候,編譯器不知道這是個什么東西,就會報警告了。
在這里插入圖片描述
怎么解決呢?那就是在前面告訴編譯器一聲,有這么個函數,這就叫函數的聲明
聲明函數只要交代清楚:函數名,函數的返回類型和函數的參數。

如:int is_leap_year(int y);
函數聲明中參數只保留類型,省略名字也是可以的(即y),因為聲明中的y不會用到,定義里才用得到。
代碼變成這樣就可以正常編譯了
在這里插入圖片描述
有的兄弟就要問了,你前面雖然把函數的定義放到前面了,但也沒有聲明呀。
那是因為函數的定義是一種特殊的聲明。

1.2 多個文件

一般在企業中寫代碼的時候,代碼可能比較多,有個幾w行,不會將所有的代碼都放到一個文件里,往往會根據程序的功能,把代碼拆分到多個文件里,這里很好理解,比如說有30個程序員,難道要他們在一個文件里寫代碼嗎,難不成還要分前后順序?就算給共享文檔也會出現問題,而且每個人都要看前一個人寫的代碼,讀起來也費勁,這不符合互相協調模塊化程序

一般情況下,函數的聲明、類型的聲明放在頭文件(add.h)中,函數的定義放在(add.c),函數的實現放在源文件(test_05_30_01.c)中,例如這樣:
在這里插入圖片描述
這里是點擊名字,進行拖拉,把三個文件放在一個窗口上看的。

補充:因為是在不同的文件中,在源文件中想要實現函數需要包含頭文件,因為文件時自己創建的,不是標準庫里提供的,所以包含的樣式有所區別:

#include"add.h"

使用雙引號就可以了。
稍作對比就可以發現,庫函數和這里的原理是對應的。
當然add.c不用必須與add.h的名字一樣,這里之所以一樣只是為了對應起來更加直觀,其他地方調用也只要包含對應的頭文件就可以了。

這樣多文件的形式就達到了以下兩種效果

  1. 方便模塊化編程
  2. 方便協作

比如現在讓5個程序員來寫一個計算器程序,這個計算機的程序可以分為4個大塊

  • 加法
  • 減法
  • 乘法
  • 除法
 A        B        C        D         E
add.c   sub.c    mul.c     div.c    test.c
add.h   sub.h    mul.h     div.h    #include"add.h"#include"sub.h"......

這樣每個程序員寫好自己的函數聲明和定義,最后一個程序員頭文件整合在一起不就方便多了嗎?

其實這里把頭文件移除,add.h的頭文件也不包含了,強行運行程序也是可以的
在這里插入圖片描述
但是會報警告,因為沒有聲明。這里還有另一種解決辦法。
因為函數來自外部文件,在(test_05_30_01.c)中聲明需要在前面加一個extern,extern是用來聲明外部符號的。
在這里插入圖片描述
這樣就不會報警告了

這里還是推薦第一種,包含頭文件的方式,因為包含頭文件其實就相當于把add.h里的聲明拷貝過來,把#include"add.h"替換掉,本質上就相當于聲明。
還有另一種好處在下一篇文章去講。
價值10w的游戲引擎該怎么賣?

1.3 static和extern

static和extern都是C語言中的關鍵字
static是靜態的的意思,可以用來:

  • 修飾局部變量
  • 修飾全局變量
  • 修飾函數

extern是用來聲明外部符號的,外部符號可以是全局變量,函數等

談起static和extern之前再講一下:作用域和生命周期

**作用域(scope)**是程序設計概念,通常來說,一段程序代碼中所用到的名字并不總是有效的,而限定這個名字的可用性的代碼范圍就是這個名字的作用域。

一句話來概括,這個名字在哪里可以使用,哪里就是作用域

  1. 局部變量的作用域就是變量坐在的局部范圍
    在這里插入圖片描述
    可以看到這里的n就是局部變量,它的范圍就是第二個{ }里面,這個{ }外的printf運行的時候就會發生報錯。

  2. 全局變量的作用域就是整個工程(項目)
    甚至在函數內,其他.c文件內也可以作用,附以代碼截圖
    在這里插入圖片描述
    在這里插入圖片描述
    在這里插入圖片描述
    不過全局變量在其他.c文件里想要使用,需要聲明外部符號extern,告訴編譯器這個n來自外部,是其他源文件的,所以全局變量無論是在哪里定義的,整個工程想使用都是可以的。

生命周期指的是變量的創建(申請內存)到變量的銷毀(收回內存)之間的一個時間段。

  1. 局部變量的生命周期是:進入作用域變量創建,生命周期開始,出作用域生命周期結束
  2. 全局變量的聲明周期是:整個程序的生命周期(即main函數的生命周期,從main函數開始到return 0)

1.3.1 static修飾局部變量

在這里插入圖片描述
正常情況下,這個程序輸出的結果就是5個2
test函數中的局部變量n是每次進入test函數先創建變量(生命周期開始)并賦值為0,然后++,再打印,出函數的時候變量生命周期將要結束(釋放內存)

但加入static修飾局部變量n之后,就輸出2,3,4,5,6
在這里插入圖片描述
稍作反推,我們就能推導出這里n具有了累加的效果,其實是test函數中的n創建好之后,出函數的時候是不會銷毀的,重新進入函數也就不會重新創建變量。

每次用的是上一次留下來的值,相當于static int n = 1;是個擺設,追究底層原理也可以進入調試轉到反匯編看一下
在這里插入圖片描述
在這里插入圖片描述
C語言代碼全轉換成匯編語句時,沒一串代碼轉換出的匯編指令數量不定,但是按f11進入函數之后,static int n = 1;無匯編指令,而且繼續按f11調試的時候,會跳過這條語句。

由此我們可以得出結論:static修飾局部變量改變了變量的生命周期,生命周期改變的本質是改變了變量的存儲類型
在這里插入圖片描述
這是代碼在內存中的存儲,本來一個局部變量時存儲在內存的棧區的,但是被static修飾后存儲到了靜態區。存儲在靜態區的變量和全局變量是一樣的,生命周期就和程序的生命周期一樣了,只有程序結束,變量才銷毀,內存才回收,但是作用域不變,即還是只能在局部變量使用。

1.3.2 static修飾全局變量

在這里插入圖片描述
這串代碼再熟悉不過了,extern是用來聲明外部符號的,如果一個全局變量的符號在A文件中定義的,在B文件中想使用,就可以使用extern進行聲明,然后使用

但是如果我們在test2.c里的全局變量n前加static后
在這里插入圖片描述
現象原因:
一個全局變量被static修飾,使得這個全局變量只能在本源文件內使用,不能在其他源文件內使用

現象解釋:
本質原因是全局變量默認是具有外部鏈接屬性的,在外部的文件中想要使用,只要是黨的聲明就可以使用。但是全局變量被static修飾之后,外部連接屬性就變成了內部連接屬性,只能在自己所在的源文件內部使用了,其他源文件,即使聲明了,也是無法正常使用的。

1.3.3 static修飾函數

這里和siatic修飾全局變量是類似的
在這里插入圖片描述
正常情況下是可以運行的
但加入static之后修飾函數之后
在這里插入圖片描述
一個函數在整個工程都可以使用,但被static修飾后,只能在本文件內部使用,其他文件無法正常的鏈接使用了

本質是因為函數默認是具有外部鏈接屬性,使得函數在整個工程中只要適當聲明就可以被使用,但是被static修飾后變成了內部鏈接屬性,使得函數只能在自己所在的源文件內部使用。

總結:當一個全局變量或函數只想在源文件內部使用,不想被其他源文件使用,就可以使用static修飾。


總結

例如:以上就是今天要講的內容,本文算是數組的徹底結束了,下一篇文章主播開始寫掃雷,主播寫這篇文章最后也是燃盡了,喜歡的兄弟們不要忘了一鍵三連給予支持。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/82125.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/82125.shtml
英文地址,請注明出處:http://en.pswp.cn/web/82125.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PySide6 GUI 學習筆記——常用類及控件使用方法(地址類QUrl)

文章目錄 地址類QUrl主要功能URL 格式介紹常見 scheme(協議)類型QUrl 類常用方法常用方法示例典型應用場景 地址類QUrl QUrl 是 PySide6.QtCore 模塊中的一個類,用于處理和操作 URL(統一資源定位符)。它可以解析、構建…

GEE:獲取研究區的DEM數據

最近有粉絲追更 GEE 系列,說上次看完 DEM 代碼解析后,自己試著改了一版。今天咱們就來拆解他的優化版代碼 ——基于 SRTM 數據獲取研究區 DEM 并導出,順便聊聊怎么把 GEE 代碼寫得更專業! 先下結論:代碼邏輯完整,3 處細節值得新手抄作業! 這版代碼在數據加載→裁剪→可…

汽車安全 2030 預測 (功能安全FuSa、預期功能安全SOTIF、網絡安全CyberSecurity):成本、效益與行業影響

汽車安全 2030 預測 (功能安全FuSa、預期功能安全SOTIF、網絡安全CyberSecurity):成本、效益與行業影響 到 2030 年,汽車行業將迎來一場安全技術的深度變革,其中 “三重安全防護”(功能安全 FuSa、預期功能安全 SOTIF、網絡安全&…

深入理解設計模式之狀態模式

深入理解設計模式之:狀態模式(State Pattern) 一、什么是狀態模式? 狀態模式(State Pattern)是一種行為型設計模式。它允許一個對象在其內部狀態發生改變時,改變其行為(即表現出不…

Redis的大Key問題如何解決?

大家好,我是鋒哥。今天分享關于【Redis的大Key問題如何解決?】面試題。希望對大家有幫助; Redis的大Key問題如何解決? 1000道 互聯網大廠Java工程師 精選面試題-Java資源分享網 Redis中的“大Key”問題是指某個鍵的值占用了過多…

【STM32開發板】接口部分

一、USB接口 可以看到USBP和USBN與PA12,PA11引腳相接,根據協議,需要添加上拉電阻 二、ADC和DAC 根據原理圖找到可以作為ADC和DAC的引腳 ADC和DAC屬于模擬部分的,所以要接模擬地 三、指示燈電路 找幾個通用的引腳,因為單片機的灌電流比拉電流…

[Hackers and Painters] 讀書筆記 | 設計模式思想 | LISP

目錄 黑客與藝術的關系 “如果你有兩個選擇,就選擇較難的那個“ 金錢不等于財富。創造有價值的東西就是創造財富 項目公式 探討關于優秀程序員的話題 摘抄 保羅格雷厄姆其人其事 人物經歷 圖書介紹 個人作品編輯 譯者序 為什么書呆子不受歡迎 黑客與畫…

Linux基本指令/下

目錄 1.echo、cat與printf 2. > 操作符 與 >> 操作符 3. < 操作符 4.消息傳送 linux文件深入 5.文件類型 6.mv命令 7.時間相關指令 8.查找命令 9.grep命令 10.zip/unzip/tar命令 11.scp命令 12.bc命令 13.uname 指令 14.快捷鍵大全 15.關機/重啟/睡…

Apptrace:APP安全加速解決方案

2021 年&#xff0c;某知名電商平臺在 “618” 大促期間遭遇 DDoS 攻擊&#xff0c;支付系統癱瘓近 2 小時&#xff1b;2022 年&#xff0c;一款熱門手游在新版本上線時因 CC 攻擊導致服務器崩潰。觀察發現&#xff0c;電商大促、暑期流量高峰和年末結算期等關鍵商業周期&#…

NodeJS全棧開發面試題講解——P1Node.js 基礎與核心機制

? 1.1 Node.js 的事件循環原理&#xff1f;如何處理異步操作&#xff1f; 面試官您好&#xff0c;我理解事件循環是 Node.js 的異步非阻塞編程核心。 Node.js 構建在 V8 引擎與 libuv 庫之上。雖然 Node.js 是單線程模型&#xff0c;但它通過事件循環&#xff08;event loop&a…

【深度學習】sglang 的部署參數詳解

SGLang 的部署參數詳解 SGLang(Structured Generation Language)是一個高性能的大語言模型推理框架,專為結構化生成和多模態應用設計。本文將全面介紹SGLang的部署參數,幫助你充分發揮其性能潛力。 ?? SGLang 項目概覽 SGLang是由UC Berkeley開發的新一代LLM推理引擎,…

MATLAB實戰:機器學習分類回歸示例

以下是一個使用MATLAB的Statistics and Machine Learning Toolbox實現分類和回歸任務的完整示例代碼。代碼包含鳶尾花分類、手寫數字分類和汽車數據回歸任務&#xff0c;并評估模型性能。 %% 加載內置數據集 % 鳶尾花數據集&#xff08;分類&#xff09; load fisheriris; X_i…

數組。。。。。

//創建Book 對象&#xff0c;放入相關的屬性private String name;//書名private String[] writer;//作者private List<String> reader;//讀者private Map<String, Object> topics;//評講Book book new Book();book.setName("昆蟲總動員");book.setWrite…

day16 leetcode-hot100-31(鏈表10)

25. K 個一組翻轉鏈表 - 力扣&#xff08;LeetCode&#xff09; 1.模擬法 思路 將這個過程拆解為兩個步驟&#xff0c;第一步將單分組的節點反轉&#xff0c;第二步將反轉后的鏈表加入原鏈表。 針對節點反轉很容易&#xff0c;參考之前的206. 反轉鏈表 - 力扣&#xff08;Le…

測試總結(二)

持續集成 軟件開發實踐 開發提交代碼到gitlab上 自動化構建&#xff08;編譯、打包、部署、自動化測試&#xff09; 盡早發現集成問題 過程&#xff1a; 提交代碼-人工/定時觸發-自動構建-自動部署-構建成功-獲取構建環境信息-郵件通知-自動測試 快速集成、快速反饋、快速解決…

(二)微服務(grpc/grpc消費者)

文章目錄 項目地址一、grpc介紹1.1 項目初始化1. 創建grpc項目2. 項目結構二、Discount grpc創建2.1 實體層1. Coupon實體2.2 Protos1. 創建discount.proto2. 配置proto3. 創建DiscountService4. Program里注冊服務2.3 Seed 數據1. 創建表和Seed數據2. 自動migration2.4 更新Do…

InfluxQL 數據分析實戰:聚合、過濾與關聯查詢全解析

InfluxQL 作為時序數據庫的專用查詢語言&#xff0c;在處理時間序列數據時展現出獨特優勢。本文深入探討 聚合計算、數據過濾和跨測量關聯 三大核心操作&#xff0c;通過真實代碼示例展示如何從海量時序數據中提取關鍵洞察。文中涵蓋從基礎平均值計算到復雜多維度分析的完整流程…

TDengine 運維——巡檢工具(安裝前檢查)

簡介 本文檔旨在介紹 TDengine 安裝部署前后配套的巡檢工具。 相關工具的功能簡介&#xff1a; 工具名稱功能簡介安裝前檢查部署前對 TDengine 安裝部署的依賴要素進行安裝前檢查安裝前預配置部署前對 TDengine 安裝部署的依賴要素進行安裝前預配置安裝部署指定環境安裝部署…

大語言模型(LLM)入門 - (1) 相關概念

文章來自&#xff1a;大語言模型(LLM)小白入門自學項目-TiaoYu-1 GitHub - tiaoyu1122/TiaoYu-1: For People! For Freedom!For People! For Freedom! Contribute to tiaoyu1122/TiaoYu-1 development by creating an account on GitHub.https://github.com/tiaoyu1122/TiaoYu…

LearnOpenGL-筆記-其十一

Normal Mapping 又到了介紹法線貼圖的地方&#xff0c;我感覺我已經寫了很多遍了... 法線貼圖用最簡單的話來介紹的話&#xff0c;就是通過修改貼圖對應物體表面的法線來修改光照效果&#xff0c;從而在不修改物體實際幾何形狀的前提下實現不同于物體幾何形狀的視覺效果。 因…