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

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

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

C語言有哪些語法技巧和功能

strongerHuang ? 來源:百問科技 ? 作者:百問科技 ? 2022-03-10 17:42 ? 次閱讀

C語言常常讓人覺得它所能表達(dá)的東西非常有限。它不具有類似第一級(jí)函數(shù)和模式匹配這樣的高級(jí)功能。但是C非常簡(jiǎn)單,并且仍然有一些非常有用的語法技巧和功能,只是沒有多少人知道罷了。

一、指定的初始化 很多人都知道像這樣來靜態(tài)地初始化數(shù)組:
int fibs[] = {1, 1, 2, 3, 5};

C99標(biāo)準(zhǔn)實(shí)際上支持一種更為直觀簡(jiǎn)單的方式來初始化各種不同的集合類數(shù)據(jù)(如:結(jié)構(gòu)體,聯(lián)合體和數(shù)組)。 二、數(shù)組 我們可以指定數(shù)組的元素來進(jìn)行初始化。這非常有用,特別是當(dāng)我們需要根據(jù)一組#define來保持某種映射關(guān)系的同步更新時(shí)。來看看一組錯(cuò)誤碼的定義,如:

/* Entries may not correspond to actual numbers. Some entries omitted. */
#define EINVAL 1
#define ENOMEM 2
#define EFAULT 3
/* ... */
#define E2BIG 7
#define EBUSY 8
/* ... */
#define ECHILD 12
/* ... */

現(xiàn)在,假設(shè)我們想為每個(gè)錯(cuò)誤碼提供一個(gè)錯(cuò)誤描述的字符串。為了確保數(shù)組保持了最新的定義,無論頭文件做了任何修改或增補(bǔ),我們都可以用這個(gè)數(shù)組指定的語法。
char *err_strings[] = {[0] = "Success",[EINVAL] = "Invalid argument",[ENOMEM] = "Not enough memory",[EFAULT] = "Bad address",/* ... */[E2BIG ] = "Argument list too long",[EBUSY ] = "Device or resource busy",/* ... */[ECHILD] = "No child processes"/* ... */};
這樣就可以靜態(tài)分配足夠的空間,且保證最大的索引是合法的,同時(shí)將特殊的索引初始化為指定的值,并將剩下的索引初始化為0。 三、結(jié)構(gòu)體與聯(lián)合體 用結(jié)構(gòu)體與聯(lián)合體的字段名稱來初始化數(shù)據(jù)是非常有用的。假設(shè)我們定義:
struct point {int x;int y;int z;}

然后我們這樣初始化struct point:
struct point p = {.x = 3, .y = 4, .z = 5};

當(dāng)我們不想將所有字段都初始化為0時(shí),這種作法可以很容易的在編譯時(shí)就生成結(jié)構(gòu)體,而不需要專門調(diào)用一個(gè)初始化函數(shù)。
對(duì)聯(lián)合體來說,我們可以使用相同的辦法,只是我們只用初始化一個(gè)字段。 四、宏列表 C中的一個(gè)慣用方法,是說有一個(gè)已命名的實(shí)體列表,需要為它們中的每一個(gè)建立函數(shù),將它們中的每一個(gè)初始化,并在不同的代碼模塊中擴(kuò)展它們的名字。這在Mozilla的源碼中經(jīng)常用到,我就是在那時(shí)學(xué)到這個(gè)技巧的。例如,在我去年夏天工作的那個(gè)項(xiàng)目中,我們有一個(gè)針對(duì)每個(gè)命令進(jìn)行標(biāo)記的宏列表。其工作方式如下:
#define FLAG_LIST(_) _(InWorklist) _(EmittedAtUses) _(LoopInvariant) _(Commutative) _(Movable) _(Lowered) _(Guard)


它定義了一個(gè)FLAG_LIST宏,這個(gè)宏有一個(gè)參數(shù)稱之為 _ ,這個(gè)參數(shù)本身是一個(gè)宏,它能夠調(diào)用列表中的每個(gè)參數(shù)。舉一個(gè)實(shí)際使用的例子可能更能直觀地說明問題。假設(shè)我們定義了一個(gè)宏DEFINE_FLAG,如:
#define DEFINE_FLAG(flag) flag,enum Flag {None = 0,FLAG_LIST(DEFINE_FLAG)Total};#undef DEFINE_FLAG
對(duì)FLAG_LIST(DEFINE_FLAG)做擴(kuò)展能夠得到如下代碼:
enum Flag {None = 0,DEFINE_FLAG(InWorklist)DEFINE_FLAG(EmittedAtUses)DEFINE_FLAG(LoopInvariant)DEFINE_FLAG(Commutative)DEFINE_FLAG(Movable)DEFINE_FLAG(Lowered)DEFINE_FLAG(Guard)Total};
接著,對(duì)每個(gè)參數(shù)都擴(kuò)展DEFINE_FLAG宏,這樣我們就得到了enum如下:
enum Flag {None = 0,InWorklist,EmittedAtUses,LoopInvariant,Commutative,Movable,Lowered,Guard,Total};
接著,我們可能要定義一些訪問函數(shù),這樣才能更好的使用flag列表:
#define FLAG_ACCESSOR(flag) bool is##flag() const {return hasFlags(1 << flag);}void set##flag() {JS_ASSERT(!hasFlags(1 << flag));setFlags(1 << flag);}void setNot##flag() {JS_ASSERT(hasFlags(1 << flag));removeFlags(1 << flag);}FLAG_LIST(FLAG_ACCESSOR)#undef FLAG_ACCESSOR

一步步的展示其過程是非常有啟發(fā)性的,如果對(duì)它的使用還有不解,可以花一些時(shí)間在gcc –E上。 五、編譯時(shí)斷言 這其實(shí)是使用C語言的宏來實(shí)現(xiàn)的非常有“創(chuàng)意”的一個(gè)功能。有些時(shí)候,特別是在進(jìn)行內(nèi)核編程時(shí),在編譯時(shí)就能夠進(jìn)行條件檢查的斷言,而不是在運(yùn)行時(shí)進(jìn)行,這非常有用。不幸的是,C99標(biāo)準(zhǔn)還不支持任何編譯時(shí)的斷言。
但是,我們可以利用預(yù)處理來生成代碼,這些代碼只有在某些條件成立時(shí)才會(huì)通過編譯(最好是那種不做實(shí)際功能的命令)。有各種各樣不同的方式都可以做到這一點(diǎn),通常都是建立一個(gè)大小為負(fù)的數(shù)組或結(jié)構(gòu)體。最常用的方式如下:
/* Force a compilation error if condition is false, but also produce a result* (of value 0 and type size_t), so it can be used e.g. in a structure* initializer (or wherever else comma expressions aren't permitted). *//* Linux calls these BUILD_BUG_ON_ZERO/_NULL, which is rather misleading. */#define STATIC_ZERO_ASSERT(condition) (sizeof(struct { int:-!(condition); }) )#define STATIC_NULL_ASSERT(condition) ((void *)STATIC_ZERO_ASSERT(condition) )/* Force a compilation error if condition is false */#define STATIC_ASSERT(condition) ((void)STATIC_ZERO_ASSERT(condition))
如果(condition)計(jì)算結(jié)果為一個(gè)非零值(即C中的真值),即! (condition)為零值,那么代碼將能順利地編譯,并生成一個(gè)大小為零的結(jié)構(gòu)體。如果(condition)結(jié)果為0(在C真為假),那么在試圖生成一個(gè)負(fù)大小的結(jié)構(gòu)體時(shí),就會(huì)產(chǎn)生編譯錯(cuò)誤。
它的使用非常簡(jiǎn)單,如果任何某假設(shè)條件能夠靜態(tài)地檢查,那么它就可以在編譯時(shí)斷言。例如,在上面提到的標(biāo)志列表中,標(biāo)志集合的類型為uint32_t,所以,我們可以做以下斷言:
STATIC_ASSERT(Total <= 32)
它擴(kuò)展為:
(void)sizeof(struct { int:-!(Total <= 32) })
現(xiàn)在,假設(shè)Total<=32。那么-!(Total <= 32)等于0,所以這行代碼相當(dāng)于:
(void)sizeof(struct { int: 0 })
這是一個(gè)合法的C代碼?,F(xiàn)在假設(shè)標(biāo)志不止32個(gè),那么-!(Total <= 32)等于-1,所以這時(shí)代碼就相當(dāng)于:
(void)sizeof(struct { int: -1 } )
因?yàn)槲粚挒樨?fù),所以可以確定,如果標(biāo)志的數(shù)量超過了我們指派的空間,那么編譯將會(huì)失敗。

原文標(biāo)題:幾點(diǎn)實(shí)用的C語言技巧

文章出處:【微信公眾號(hào):strongerHuang】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

審核編輯:彭菁

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

    關(guān)注

    180

    文章

    7581

    瀏覽量

    135564
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4258

    瀏覽量

    62227
  • 編譯
    +關(guān)注

    關(guān)注

    0

    文章

    647

    瀏覽量

    32741

原文標(biāo)題:幾點(diǎn)實(shí)用的C語言技巧

文章出處:【微信號(hào):strongerHuang,微信公眾號(hào):strongerHuang】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    C語言基本概念及語法

    C語言基本概念和語法供初學(xué)者研討
    發(fā)表于 08-18 10:32

    C語言語法錯(cuò)誤

    [url=]C語言語法錯(cuò)誤[/url]
    發(fā)表于 04-07 14:25

    嵌入式系統(tǒng)常用的C語言基本語法哪些

    嵌入式系統(tǒng)常用的C語言基本語法概要
    發(fā)表于 10-27 08:33

    Linux內(nèi)核中GNU C擴(kuò)展的一些常用C語言語法分析

    13.1 總結(jié)前面12節(jié)的課程,主要針對(duì) Linux 內(nèi)核中 GNU C 擴(kuò)展的一些常用 C 語言語法進(jìn)行了分析。GNU C 的這些擴(kuò)展語法
    發(fā)表于 12-14 06:29

    C語言的特點(diǎn)哪些呢

    1.從語言特點(diǎn)來說①C語言出色的可移植性,能在多種不同體系結(jié)構(gòu)的軟/硬平臺(tái)上運(yùn)行。②簡(jiǎn)潔緊湊,使用靈活的語法機(jī)制,并能直接訪問硬件能夠直接
    發(fā)表于 12-15 08:16

    C++語法的外圍基礎(chǔ)

    程序?qū)?nèi)存空間的動(dòng)態(tài)分配的頻繁程度要求簡(jiǎn)化語言的相關(guān)語法的格式。C++語法規(guī)定new算符等效于C語言
    發(fā)表于 03-15 16:55 ?10次下載

    C語言誤用易錯(cuò)知識(shí)點(diǎn)與基本語法匯總

    語言之所以能稱之為語言,它肯定是一種工具一種相互交流相互通信相互傳達(dá)之間的意圖的工具,作為語言那肯定得有自己的語法,要想相互交流肯定得先學(xué)好它的語法
    發(fā)表于 05-05 15:32 ?2015次閱讀

    嵌入式C語言中的union語法的作用是什么

    C語言中的結(jié)構(gòu)體語法是非常重要,也是非常有用的,相信看了最近幾節(jié)的讀者應(yīng)該明白。事實(shí)上,在實(shí)際的C語言項(xiàng)目開發(fā)中,為了代碼的簡(jiǎn)潔性,描述問題
    發(fā)表于 08-29 17:10 ?1816次閱讀

    為什么要用C語言實(shí)現(xiàn)面向?qū)ο?/a>

    不知道多少人去了解過語言的發(fā)展史,早期C語言語法功能其實(shí)比較簡(jiǎn)單。隨著應(yīng)用需求和場(chǎng)景的變化,
    的頭像 發(fā)表于 11-05 18:05 ?1668次閱讀
    為什么要用<b class='flag-5'>C</b><b class='flag-5'>語言</b>實(shí)現(xiàn)面向?qū)ο? />    </a>
</div>                            <div   id=

    C語言是如何實(shí)現(xiàn)面向?qū)ο蟮?/a>

    ? ? 不知道多少人去了解過語言的發(fā)展史,早期C語言語法功能其實(shí)比較簡(jiǎn)單。隨著應(yīng)用需求和場(chǎng)景
    的頭像 發(fā)表于 12-24 17:08 ?2w次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>是如何實(shí)現(xiàn)面向?qū)ο蟮? />    </a>
</div>                            <div   id=

    Prel語法C語言語法的異同綜述

    Prel語法C語言語法的異同綜述
    發(fā)表于 05-25 11:44 ?6次下載

    嵌入式系統(tǒng)常用的C語言基本語法概要

    嵌入式系統(tǒng)常用的C語言基本語法概要
    發(fā)表于 10-20 12:51 ?6次下載
    嵌入式系統(tǒng)常用的<b class='flag-5'>C</b><b class='flag-5'>語言</b>基本<b class='flag-5'>語法</b>概要

    為什么要用C語言實(shí)現(xiàn)面向?qū)ο?/a>

      不知道多少人去了解過語言的發(fā)展史,早期C語言語法功能其實(shí)比較簡(jiǎn)單。隨著應(yīng)用需求和場(chǎng)景的變
    的頭像 發(fā)表于 02-16 16:19 ?1843次閱讀
    為什么要用<b class='flag-5'>C</b><b class='flag-5'>語言</b>實(shí)現(xiàn)面向?qū)ο? />    </a>
</div>                            <div   id=

    C語言語法擴(kuò)展

    大家在看一些 GNU 開源軟件,或者閱讀 Linux 內(nèi)核、驅(qū)動(dòng)源碼時(shí)會(huì)發(fā)現(xiàn),在 Linux 內(nèi)核源碼中,大量的 C 程序看起來“怪怪的”。說它是C語言吧,貌似又跟教材中的寫法不太一
    的頭像 發(fā)表于 02-17 09:34 ?942次閱讀

    C語言實(shí)現(xiàn)面向?qū)ο蟮姆椒?/a>

    不知道多少人去了解過語言的發(fā)展史,早期C語言語法功能其實(shí)比較簡(jiǎn)單。隨著應(yīng)用需求和場(chǎng)景的變化,
    的頭像 發(fā)表于 03-08 10:18 ?779次閱讀