0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C語言的include沒你想的那么簡單(圖文版)

嵌入式軟件實(shí)戰(zhàn)派 ? 來源:嵌入式軟件實(shí)戰(zhàn)派 ? 2023-06-08 16:44 ? 次閱讀
C語言中的include很簡單,但不是你想象中的簡單。(如果你不想看以下文字內(nèi)容,可以查看本文對應(yīng)的視頻版) 你對#include的認(rèn)識(shí)是不是只停留在包含頭文件的認(rèn)知中,好像也沒有別的用處,小小東西也翻不起什么風(fēng)浪?
#include 
#include"user_header.h"
// bala bala
#include就是包含頭文件用的,不是嗎?! 我之前也一直這么認(rèn)為的,直到我看了某些大神寫的代碼,后來我還特意查閱了C99標(biāo)準(zhǔn)。 人家是這么用的
#defineDET_START_SEC_VAR_INIT_UNSPECIFIED
# include "MemMap.h" 


# define DET_STOP_SEC_VAR_INIT_UNSPECIFIED
# include "MemMap.h" 


# define DET_START_SEC_VAR_NOINIT_8BIT
#include"MemMap.h"


# define DET_STOP_SEC_VAR_NOINIT_8BIT
# include "MemMap.h"
還有這樣用的
#defineSTRUCT_GEN_START


#include "defines.h"
#include"param_gen.h"


#include "defines.h"
#include "param_gen.h"


#include "defines.h"
#include "param_gen.h"


#include "defines.h"
#include "param_gen.h"


#include "defines.h"
#include "param_gen.h"
當(dāng)時(shí),看得我一愣一愣的…… 其實(shí),簡單來說,#include就是“包含”某個(gè)文件的意思,但這個(gè)“”,不能將思維限死在“頭文件”這個(gè)概念中,而應(yīng)該有更多的想象!#include在C語言中,算是預(yù)編譯指令(preprocessing directive)范疇,而預(yù)編譯指令在C語言就是一個(gè)大學(xué)問了。但是,我們先不要被這個(gè)“預(yù)編譯指令”名稱繞暈。上文,我們提到了頭文件這個(gè)概念,當(dāng)然我們也知道還有一個(gè)叫源文件的概念。這些我就不解釋了。但是,在C99標(biāo)準(zhǔn)中有一段這樣的話,需要研究下:

Asourcefiletogetherwithalltheheadersandsourcefilesincludedviathepreprocessingdirective#includeisknownasapreprocessingtranslationunit.Afterpreprocessing,apreprocessingtranslationunitiscalledatranslationunit.

ISO/IEC 9899:1999 (E)
簡單地理解,一個(gè)source file和一些由#include包含著的headers和source files,通過預(yù)編譯后,變成一個(gè)叫translation unit的東西。 從這里可以看出來,#include不但可以包含headers,還可以包含source files。 所以,我下面這個(gè)#include "add.h"#include "minus.c"都是正確的,編譯一點(diǎn)問題都沒有。
//main.c
#include "add.h"
#include "minus.c"


int add(int a, int b)
{
    return a+b;
}


int main(void)
{
    int c = add(1,2);
    int d = minus(2-1);
    return 0;
}
//add.h
externintadd(inta,intb);
//minus.c
int minus(int a, int b)
{
    return a-b;
}
不妨將腦洞開大一點(diǎn),除了*.h和*.c文件,我還可以include點(diǎn)別的么?答:可以。例如
//main.c
#include"multiply.txt"


int main(void)
{
inte=multiply(2,2);
    return 0;
}
甚至,這樣也行
//main.c
#include"devide.fxxk"


int main(void)
{
intf=devide(2,2);
    return 0;
}
繼續(xù)啊,#include不是放在文件上方,放中間行么。當(dāng)然
//main.c
int main(void)
{
#include"squel.xx"
intg=squel(2,2);
    return 0;
}
好家伙,這么下去,我是不是可以這么干
//data.txt
1,2,3,4,5,6,7,8,9
//main.c
int arr[] = 
{
    #include "data.txt"
}


int main(void)
{
    return 0;
}
然后,你又好奇了,能不能將data.txt換成二進(jìn)制形式的data.bin?呵呵,這種不行,編譯器在預(yù)編譯階段只認(rèn)得是text文本才行。好吧……你不是說這是個(gè)預(yù)編譯指令嗎,我很好奇,#include預(yù)編譯后成啥樣子的?這好辦,動(dòng)動(dòng)手指頭,一個(gè)gcc -E命令即可搞定。就以上面第一個(gè)例子,命令行執(zhí)行g(shù)cc ./main.c -E -o main.i
# 0 ".\main.c"
# 0 ""
# 0 "<命令行>"
# 1 ".\main.c"


# 1 "add.h" 1
extern int add(int a, int b);
# 3 ".\main.c" 2
# 1 "minus.c" 1
int minus(int a, int b)
{
    return a-b;
}
# 4 ".\main.c" 2


int add(int a, int b)
{
    return a+b;
}


int main(void)
{
    int c = add(1,2);
    int d = minus(2-1);
    return 0;
}

看到了吧,#include就是把它后面的文件內(nèi)容直接include進(jìn)來。就這么簡單粗暴。那么#include在C語言中是不是很簡單?你說呢!我見過有人這么寫代碼的,還TM的一整個(gè)團(tuán)隊(duì)是這么做的。將整個(gè)所以.h文件全部包含在一個(gè)includes.h的頭文件中,然后在其他.c文件里面,就直接#include "includes.h"。
// includes.h
#include "adc.h"
#include "uart.h"
#include "spi.h"
#include "iic.h"
#include "dma.h"
#include "pwm.h"
#include"pin.h"
#include "led.h"
#include "os.h"
#include "timer.h"
...
TM的簡便。我第一次見到這玩意,簡直是驚呆了,還有這種操作。不好嗎?有什么不好?多簡潔??!從上面的分析看,#include就是將它后面包含的頭文件源文件,全部展開哦。簡潔?你問過編譯器啥感受么?帶來的最直接的感受是,編譯過程慢!includes.h里包含得越多就越慢!另外一個(gè)隱含的問題是,會(huì)造成include里的內(nèi)容混亂,頭文件里的內(nèi)容全部是全局的了。我絕對不推薦這種玩法的。因?yàn)?,預(yù)編譯還有更好玩的玩法。不過,在介紹新玩法之前,得想個(gè)問題,如果一個(gè)頭文件,重復(fù)包含多次會(huì)怎樣?也許,你會(huì)回答,我是不允許出現(xiàn)這種情況的,就算出現(xiàn)這種情況,我也可以用#ifdef...#endif這種方式規(guī)避。如果你是應(yīng)屆生面試,這樣回答,面試官也許是點(diǎn)點(diǎn)頭說你有點(diǎn)經(jīng)驗(yàn)的。因?yàn)橹貜?fù)include,就相當(dāng)于把頭文件重復(fù)展開了多次,C語言中有些定義是不允許重復(fù)多次的。例如,上面的例子
// main.c
#include "add.h"
#include "minus.c"
#include "minus.c"

這樣是有問題的,因?yàn)樯厦嫦喈?dāng)于重復(fù)定義了兩次int minus(int a,int b)函數(shù)了。
In file included from .main.c:4:
minus.c:1:5: 錯(cuò)誤:‘minus’重定義
    1 | int minus(int a, int b)
      |     ^~~~~
如果將minus.c改成這樣就行了
#ifndef _MINUS_
#define _MINUS_
int minus(int a, int b)
{
    return a-b;
}
#endif
這個(gè)簡單啊,我也會(huì)啊。嗯,但是,我不是想說這個(gè),我真的想說重復(fù)include有意想不到的好處呢。這就不得不提下,我以前寫的X-MACRO大法了。以下是一個(gè)MEMORY字段分配的設(shè)想:
  1. Memory

  2. MemoryBlock,0

  3. 數(shù)據(jù)

  4. 應(yīng)實(shí)內(nèi)

  5. 據(jù)Memory

我想定義一些內(nèi)容條目,這些條目分別對應(yīng)不同的內(nèi)存地址,不同的長度,以后有需要還可以繼續(xù)從后面添加就這樣:
entry name address size
ID_DATA1 0 8
ID_DATA2 8 8
ID_DATA3 16 16
...
可以在一個(gè)頭文件里面做這樣的定義
// defines.h
#ifdef ENTRY_ID
  #define ENTRY(id,addr,size) id,
  #undef ENTRY
  #undef ENTRY_ID
#endif


#ifdef ENTRY_ADDR
  #define ENTRY(id,addr,size) addr,
  #undef ENTRY
  #undef ENTRY_ADDR
#endif


#ifdef ENTRY_SIZE
  #define ENTRY(id,addr,size) size,
  #undef ENTRY
  #undef ENTRY_SIZE
#endif
接著在C文件里面這么玩?
//memory.c
#define ALL_ENTRIES()       
    ENTRY(ID_DATA1, 0, 8)   
    ENTRY(ID_DATA2, 8, 8)   
    ENTRY(ID_DATA3, 16, 16) 
    ENTRY(ID_DATA4, 32, 8)


#define ENTRY_ID
#include "defines.h"
typedef enum
{
    ALL_ENTRIES()
    MEM_ID_MAX
} MEM_ID;


#define ENTRY_ADDR
#include "defines.h"
const uint32_t mem_addr[] =
{
    ALL_ENTRIES()
};


#define ENTRY_SIZE
#include "defines.h"
const uint16_t mem_size[] =
{
    ALL_ENTRIES()
};

你也許會(huì)反問我,定義一個(gè)結(jié)構(gòu)體不就搞定了嗎?別急,這樣做的好處是enum的ID順序跟addr和size是一一對應(yīng)的,不會(huì)錯(cuò)亂,另一個(gè)好處是,可以隨便在ALL_ENTRIES()下面擴(kuò)展條目,也不影響ID的對應(yīng)關(guān)系。如果用結(jié)構(gòu)體去定義的話,也很好,但是會(huì)增加數(shù)組遍歷時(shí)間,如果是很龐大的條目數(shù)的話,這個(gè)效率問題就要考慮了。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7575

    瀏覽量

    134079
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4671

    瀏覽量

    67766

原文標(biāo)題:C語言的include沒你想的那么簡單(圖文版)

文章出處:【微信號(hào):embedded_sw,微信公眾號(hào):嵌入式軟件實(shí)戰(zhàn)派】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    簡單C語言

    簡單C語言簡單C語言簡單
    發(fā)表于 07-14 20:12

    C語言基礎(chǔ)怎么學(xué)51單片機(jī)呢

    C語言基礎(chǔ)怎么學(xué)51單片機(jī)呢?為什么學(xué)好C語言卻不會(huì)弄單片機(jī)呢 ?
    發(fā)表于 10-18 09:17

    簡單信號(hào)發(fā)生器源程序C語言代碼

    簡單信號(hào)發(fā)生器源程序C語言代碼 #include #include #include #def
    發(fā)表于 04-07 08:32 ?2948次閱讀

    C語言入門教程-if語句和while循環(huán)

    if語句和while循環(huán) C語言中,if語句和while循環(huán)都會(huì)用到布爾表達(dá)式。下面是一個(gè)使用if語句的簡單例子: #include
    發(fā)表于 07-29 10:48 ?8446次閱讀

    Verilog HDL語言的文件調(diào)用問題:include使用方法介紹

    本文簡單介紹在使用Verilog HDL語言時(shí)文件的調(diào)用問題之include使用方法介紹及舉例說明,詳見本文...
    發(fā)表于 01-24 14:40 ?6669次閱讀
    Verilog HDL<b class='flag-5'>語言</b>的文件調(diào)用問題:<b class='flag-5'>include</b>使用方法介紹

    C語言簡單概述

    C語言簡介C語言簡介C語言簡介C
    發(fā)表于 11-20 14:14 ?0次下載

    pid算法原理和C語言簡單實(shí)現(xiàn)

    pid算法原理和C語言簡單實(shí)現(xiàn),有興趣的可以看看
    發(fā)表于 12-07 18:34 ?9次下載

    單片機(jī)蜂鳴器簡單發(fā)聲程序【C語言版】

    單片機(jī)蜂鳴器簡單發(fā)聲程序【C語言版】單片機(jī)蜂鳴器簡單發(fā)聲程序【C語言版】單片機(jī)蜂鳴器
    發(fā)表于 12-29 13:53 ?0次下載

    C語言教程之簡單計(jì)算器

    C語言教程之簡單計(jì)算器,很好的C語言資料,快來學(xué)習(xí)吧。
    發(fā)表于 04-25 09:38 ?0次下載

    簡單實(shí)用——C語言入門程序練習(xí)

    C語言入門程序練習(xí),簡單實(shí)用
    發(fā)表于 04-04 10:14 ?31次下載

    C語言簡單介紹

    C語言是一門面向過程的、抽象化的通用程序設(shè)計(jì)語言,廣泛應(yīng)用于底層開發(fā)。C語言能以簡易的方式編譯、處理低級存儲(chǔ)器。
    發(fā)表于 01-02 08:00 ?1次下載

    使用單片機(jī)實(shí)現(xiàn)T6963C液晶圖文演示的C語言程序設(shè)計(jì)實(shí)例免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是使用單片機(jī)實(shí)現(xiàn)T6963C液晶圖文演示的C語言程序設(shè)計(jì)實(shí)例免費(fèi)下載。
    發(fā)表于 03-30 15:52 ?23次下載

    設(shè)計(jì)模式:簡單工廠模式——基于C語言

    設(shè)計(jì)模式:簡單工廠模式——基于C語言背景 看了劉偉、胡志剛的《C#設(shè)計(jì)模式(第二版)》——清華大學(xué)出版社,利用里面闡述的簡單工廠模式創(chuàng)造一
    發(fā)表于 01-13 13:45 ?6次下載
    設(shè)計(jì)模式:<b class='flag-5'>簡單</b>工廠模式——基于<b class='flag-5'>C</b><b class='flag-5'>語言</b>

    C語言include你想那么簡單

    C語言中的include簡單,但不是你想象中的簡單。 你對#
    發(fā)表于 07-06 09:30 ?276次閱讀

    C語言中的include有什么用

    C語言中的include簡單,但不是你想象中的簡單。 你對#
    發(fā)表于 07-06 09:30 ?960次閱讀