最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

【C/C++】GNUC實(shí)現(xiàn)日志庫

2023-07-14 16:44 作者:冒-_-泡  | 我要投稿

C++日志庫,網(wǎng)上也不少了,很多是流式風(fēng)格的:

這種風(fēng)格在復(fù)雜日志的時(shí)候,代碼有一點(diǎn)亂:

很多人更喜歡C的風(fēng)格,清晰緊湊:

然而,C語言中實(shí)現(xiàn)這種類似printf的函數(shù),可能會(huì)導(dǎo)致格式和參數(shù)不匹配的UB,C++則可利用重載和模板來實(shí)現(xiàn)參數(shù)接收、封裝,進(jìn)一步用運(yùn)行時(shí)檢查,我之前寫過一個(gè)SmartPrintf(https://www.bilibili.com/read/cv18033957),但是代碼復(fù)雜且有運(yùn)行時(shí)消耗

作為標(biāo)準(zhǔn)庫的函數(shù),printf是有特殊優(yōu)待的,如果fmt字段是字符串字面量,則大多數(shù)現(xiàn)代編譯器會(huì)進(jìn)行檢查,在格式和數(shù)據(jù)類型不匹配時(shí)報(bào)警:

但日志庫是我們自己實(shí)現(xiàn)的,就沒這個(gè)待遇了:

編譯器沒檢查出來錯(cuò)誤,只能運(yùn)行時(shí)出問題了

能讓它也有這樣的待遇嗎?GNUC提供了擴(kuò)展屬性來支持:

GNUC擴(kuò)展中,我們可以用__attribute__給各種語法元素(函數(shù)、類型、語句……等等)添加屬性修飾,來告訴編譯器一些信息,從而擴(kuò)展它的行為

在這里,函數(shù)log的定義中使用了屬性修飾,修飾類型是format,內(nèi)容則是告訴編譯器,這個(gè)log函數(shù)的簽名是類似printf的樣式(其實(shí)就是要求編譯器做個(gè)檢查),format的第一個(gè)參數(shù)指明樣式(printf),第二個(gè)參數(shù)是函數(shù)簽名中fmt的位置(log的第1個(gè)參數(shù)),第三個(gè)參數(shù)是指明可變參數(shù)域從第幾個(gè)參數(shù)開始(log的第2個(gè)參數(shù)位置),這樣一來,編譯器就能獲取到對(duì)應(yīng)的信息,從而做和標(biāo)準(zhǔn)庫一樣的檢查了

和printf類似的標(biāo)準(zhǔn)庫接口,也都有對(duì)應(yīng)的檢查屬性,例如scanf、strftime等和格式有關(guān)的,編譯器都可以幫你檢查fmt串,比如說還是上面的log函數(shù),我們要給它加上一個(gè)時(shí)間打印,但又希望能自定義時(shí)間格式,就可以:

這里可以簡單通過set_time_fmt函數(shù),來設(shè)置全局變量time_fmt為自定義的時(shí)間格式,同樣的道理,這個(gè)函數(shù)通過屬性修飾,可以讓編譯器幫忙檢查設(shè)置的fmt是不是strftime需要的格式(當(dāng)然,這個(gè)fmt也必須通過字符串字面量來設(shè)置,否則沒辦法檢查)

回到日志內(nèi)容打印,上面的代碼中我們看到,log的簽名和printf是一樣的,含義也一樣,而且下層實(shí)際也是調(diào)用printf來打印,為了處理可變參數(shù)“...”域,標(biāo)準(zhǔn)C必須用到va_arg,而GNUC在這里提供了更簡單的做法,有一個(gè)內(nèi)建函數(shù)可以直接傳遞可變參數(shù)域:

__builtin_va_arg_pack這個(gè)內(nèi)建函數(shù)的“調(diào)用”,就像是把當(dāng)前函數(shù)的可變參數(shù)“...”直接寫在這里一樣,這樣就省的用va_arg了,顯然就像我之前文章講過的,這種“內(nèi)建函數(shù)”并不是一個(gè)真正的函數(shù),所以這里也不是真正的“調(diào)用”,只是給編譯器看的,類似宏替換的一個(gè)代碼標(biāo)記

因此要使用這個(gè)內(nèi)建函數(shù),編譯器必須同時(shí)知道調(diào)用者調(diào)用時(shí)的輸入,所以這個(gè)函數(shù)必須是強(qiáng)制內(nèi)聯(lián)(上面用always_inline屬性修飾),且因?yàn)槭菑?qiáng)制內(nèi)聯(lián),其實(shí)現(xiàn)也必須被使用者可見(也就是說,一般得寫到頭文件中)。由于這些限制,可變參數(shù)的這種直接透?jìng)鞯姆绞?,一般只用于相關(guān)接口的簡單封裝中,避免使用va_args的麻煩

對(duì)于一個(gè)log來說,還有一個(gè)重要的內(nèi)容是日志打印的代碼位置,如果要結(jié)合可變參數(shù)域,那么這個(gè)就只能通過宏來實(shí)現(xiàn)了,可以用標(biāo)準(zhǔn)的__FILE__和__LINE__宏,但既然是講GNUC,最推薦的還是對(duì)應(yīng)的內(nèi)建函數(shù):


【C/C++】GNUC實(shí)現(xiàn)日志庫的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
大竹县| 略阳县| 巴林右旗| 呼和浩特市| 揭东县| 兴安县| 宾川县| 思茅市| 峨眉山市| 小金县| 麦盖提县| 丹凤县| 岑巩县| 名山县| 渝中区| 连平县| 思茅市| 武强县| 新源县| 丹江口市| 德化县| 中宁县| 揭西县| 大厂| 海南省| 泗水县| 长治县| 仁布县| 茌平县| 应用必备| 镇雄县| 衢州市| 西青区| 合川市| 铁岭县| 阆中市| 文水县| 封开县| 隆林| 龙游县| 兴国县|