久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

標題: C語言頭文件編寫方法 [打印本頁]

作者: lining123    時間: 2019-6-15 22:45
標題: C語言頭文件編寫方法
認真說起來,頭文件(Header File)是個短命的家伙——就整個編譯過程來說,它的壽命是最短的。
為什么這么說呢?關于頭文件的話題,討論起來那可是孩子沒娘,說來話長了,既然是閑聊、你也不
是等著這篇文章救命,那就不妨從頭開始說起——先假設讀者們都是不了解編譯基本過程的初學者。

   
一個編譯(Compilation)過程通常至少分為三個階段:預編譯(Precompiling)、編譯(Make)和鏈接
Linking)。他們就像一個流水線一環套一環——前一工序的輸出是后一工序的輸入。這本沒有什么稀奇的,
但對于程序員來說,這個過程中有幾個基本常識是需要記住的:


1. C
語言編譯的基本單位(Compilation Unit)是 C源文件(而并沒有頭文件)
2.
同一個工程中,不同C源文件的編譯是彼此獨立的(毫不相干的)
3.
頭文件在預編譯階段就已經合并到對應的C源文件中了,和所有的宏以及條件編譯一樣,到了編譯階段,所有的頭文件、宏都是不存在的,已經被替換為對應的內容和常量了。


   
理解這三點,基本上已經可以解決很多我們日常編碼過程中存在的很多疑問,比如:


- Q1
:為什么不能C語言頭文件里面定義變量或者函數的實體?
- Q2
:為什么有的時候宏的先后順序并不那么重要?
- Q3
:為什么可以在源代碼的任意位置(另起一行后)定義宏,甚至是include別的頭文件?

   
推薦大家基于前面的三個事實自己思考,答案在附錄中介紹。
   
   
頭文件里可以放什么呢?這是個值得討論的問題:


-  各類宏
-  函數的聲明(也就是 extern xxxxx
-  全局變量的聲明(也就是 extern xxxx
   然而,值得說明的是,這里有一個編碼規則值得你去遵守:頭文件里堅決不要放全局變量有關的任何東西(硬要加,也必須是const類型的,比如各類接口)
-  類型定義(typedef, struct,union 之類的)
-  static 的變量實體和函數實體。
   這個可以有,為啥呢?因為即便多個c源文件包含同一個頭文件導致同樣的函數和變量實體存在多份,但
   static 的另外一個名字 "private" 可以保證每一份變量和函數實體都是彼此獨立的,都是每個c源代碼的
   私人財產——你可以有,我也可以有。“哎?你也有啊,真巧哎,我也有……”
-  inline 的函數
   這個和static是一個道理。


   
頭文件里面不能放函數的實體,想必原因大部分人都知道了,這里就不再贅述。但頭文件里不放(非const)的全局變量的聲明,
這怎么玩?這里需要說明一下,頭文件里不是不能放(非const)的全局變量聲明,而是我提供了一個人為的規定(規范),建議
不要放任何(非const)的全局變量到頭文件里,具體原因和解決方案,我們在別的帖子里再討論(其實有人討論過,大約就是,
如何避免使用全局變量)——是的,避免使用(非const)的全局變量是可以做到的——這里也不再贅述。說了這么多廢話,我們
真正要討論的內容還沒有開始:


- 如何建立頭文件的使用規則,使其即靈活、使用方便,又靈活且便于擴展(模塊化)——符合面向接口開發的要求,方便我們
  
建立黑盒子?
簡而言之,
-
如何讓頭文件的使用不再頭疼;永遠告別循環包含;方便代碼的移植?



      
首先,思考一個簡單的問題?為什么我們要用頭文件?答案其實很簡單,因為每個.c文件都是獨立編譯的,因此需要在源代碼
級別傳遞一些信息,類似一群人在嘮嗑:

   
   
源代碼A             我定義了一個函數,你們哥幾個要用么?
   
源代碼B和源代碼C 我們要用啊,函數原型(prototype)什么樣子啊?
   
源代碼A              你們不用費腦經記(抄下來),我都寫好了,放在一個頭文件里了,你們直接include就可以了。
   
源代碼B和源代碼C 這個敢情方便。那你頭文件放哪里了?
   
源代碼A              有兩種方式,要么你直接到我這里來拿(指定路徑);要么你找編譯器問(編譯器指定搜索路徑)。
   
源代碼D              你們整這么麻煩做什么?你直接告訴我原型,我抄下來,不就不用問這個問那個,還包含文件什么的,真麻煩。
   
源代碼A              D啊,你老想耍小聰明,萬一我更新了你不知道怎么辦?我有義務告訴你么?并沒有。
   
源代碼B和源代碼C 是啊,是啊,A以后估計要外包了,不在這里了,到時候有變化,都記錄在頭文件里,你本地放一個,沒法
                                       
及時同步的。
   
源代碼D             我不聽!我不聽!我不聽……


   
是不是很有畫面感?拋開捂著耳朵的D,我們回到討論的話題——既然頭文件是用來交換信息的,那么如果把所有的信息都放在一起,大家
需要的時候各取所需,豈不美哉?——基于這種思想,幾乎所有人都見過把所有變量、函數、宏、類型定義都放到一個叫做system.h的頭文件
里的做法。你有這么做過么?不要不好意思,幾乎所有人都這么做過——因為實在太方便了,世界大同,挺好,直到你嘗試和別人一起合作開發
系統,并試圖在不同項目間復用一些代碼的時候:

    “
何首烏藤和木蓮藤纏絡著”……對于這種情況,我們叫做耦合。是要找個時間來理一理了,你對自己說,然后長嘆了一口氣,發現這句話其
實很早之前就說過了。想到還有更奇葩的循環包涵的問題,你不得不感嘆,頭文件真的是個頭疼的東西——要不我們還是不用了吧?直接抄下來
貌似更簡單啊——源程序D癡癡的笑了。

   
那么,如何解決這個問題呢?其實,從實踐經驗來看,頭文件的用途分為兩大類:

   
站在C源文件的視角上:


- 從 外部向C源文件內部 輸入配置信息——我們把這類頭文件叫做配置頭文件(Configuration HeaderFile)。
  需要強調的是,信息的流動方向是 從外向內,所以又可以簡單的理解為輸入性的頭文件(Header File for information input)。常見的app_cfg.h
  就是典型的配置頭文件。

- 從 C源文件內部向外 輸出接口信息(全局函數、類型,宏定義等信息)——我們把這類頭文件叫做接口頭文件(Interface Header File)。
  需要強調的是,信息的流動方向是 從內向外,所以又可以簡單的理解為輸出性的頭文件(Header File for information output)。常見的, spi.h
  usart.h, device.h, stdint.h 就是典型的接口頭文件。


   
輸入和輸出兩個不同的職能如果被放在同一個頭文件里,就有極大的風險產生循環包含(兩個相反方向的箭頭產生閉合的圓圈)。system.h實際
上就是一個混淆信息流動方向的例子。這就是本質上依賴system.h的工程 模塊不好拆分的原因。根據上述原理,這里引入頭文件使用的第一條原則:


   
對一個C源代碼來說,站在它的視角上,隸屬于它自己的接口頭文件(Output)和配置頭文件(Input)永遠不要同時包含(include)在當前
C源文件中。

全部資料51hei下載地址:
頭文件編寫.docx (332.33 KB, 下載次數: 52)

作者: jxchen    時間: 2019-6-23 14:24
下來看看,感謝分享
作者: tieq1952    時間: 2019-9-4 07:49
謝謝分享!!!




歡迎光臨 (http://www.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: 一区二区三区四区五区在线视频 | 欧美日韩精品一区二区三区四区 | 亚洲中午字幕 | 九九精品久久久 | 丁香婷婷成人 | 亚洲一区二区久久 | 性xxxxx| 蜜桃视频一区二区三区 | 亚洲毛片在线观看 | 欧美一级片a | 免费人成在线观看网站 | 一区二区中文字幕 | 久久亚洲综合 | 精品欧美乱码久久久久久 | 亚洲综合色视频在线观看 | www.久久影视| 一区二区在线看 | 久久国产视频网站 | 国产成人免费视频 | www.一级片| 福利视频日韩 | 亚洲国产精品激情在线观看 | 色婷婷精品久久二区二区蜜臂av | av一二三区| 日韩精品一区二区三区中文在线 | 久久综合色综合 | 欧美激情精品久久久久久变态 | 亚洲综合第一页 | 污视频在线免费观看 | 日韩成人精品在线 | 国产日韩一区 | 久久99久久99 | 男女羞羞免费网站 | 亚洲综合在线一区 | 亚洲免费在线播放 | 91视频在线 | 日日夜夜精品免费视频 | 91精品国产综合久久久亚洲 | 天天插天天射天天干 | 精品欧美一区二区三区久久久 | 日韩欧美一区在线 |