www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 嵌入式大雜燴
[導(dǎo)讀]點(diǎn)擊上方「嵌入式大雜燴」,選擇「置頂公眾號(hào)」第一時(shí)間查看嵌入式筆記!來(lái)源:CSDN01.調(diào)試相關(guān)的宏在Linux使用gcc編譯程序的時(shí)候,對(duì)于調(diào)試的語(yǔ)句還具有一些特殊的語(yǔ)法。gcc編譯的過(guò)程中,會(huì)生成一些宏,可以使用這些宏分別打印當(dāng)前源文件的信息,主要內(nèi)容是當(dāng)前的文件、當(dāng)前運(yùn)行的...

點(diǎn)擊上方「嵌入式大雜燴」,選擇「置頂公眾號(hào)」第一時(shí)間查看嵌入式筆記!

來(lái)源:CSDN

01.調(diào)試相關(guān)的宏

在Linux使用gcc編譯程序的時(shí)候,對(duì)于調(diào)試的語(yǔ)句還具有一些特殊的語(yǔ)法。

gcc編譯的過(guò)程中,會(huì)生成一些宏,可以使用這些宏分別打印當(dāng)前源文件的信息,主要內(nèi)容是當(dāng)前的文件、當(dāng)前運(yùn)行的函數(shù)和當(dāng)前的程序行。

具體宏如下:

__FILE__??當(dāng)前程序源文件?(char*)
__FUNCTION__??當(dāng)前運(yùn)行的函數(shù)?(char*)
__LINE__??當(dāng)前的函數(shù)行?(int)
這些宏不是程序代碼定義的,而是有編譯器產(chǎn)生的。這些信息都是在編譯器處理文件的時(shí)候動(dòng)態(tài)產(chǎn)生的。

「測(cè)試示例:」

#include?

int?main(void)
{
????printf("file:?%s\n",?__FILE__);
????printf("function:?%s\n",?__FUNCTION__);
????printf("line:?%d\n",?__LINE__);

????return?0;
}

02.# 字符串化操作符

在gcc的編譯系統(tǒng)中,可以使用#將當(dāng)前的內(nèi)容轉(zhuǎn)換成字符串。

「程序示例:」

#include?

#define?DPRINT(expr)?printf("
%s?=?%d\n",?#expr,?expr);

int?main(void)
{
????int?x?=?3;
????int?y?=?5;

????DPRINT(x?/?y);
????DPRINT(x? ?y);
????DPRINT(x?*?y);
????
????return?0;
}
「執(zhí)行結(jié)果:」

deng@itcast:~/tmp$?gcc?test.c?
deng@itcast:~/tmp$?./a.out??
x?/?y?=?0
x? ?y?=?8
x?*?y?=?15
#expr表示根據(jù)宏中的參數(shù)(即表達(dá)式的內(nèi)容),生成一個(gè)字符串。該過(guò)程同樣是有編譯器產(chǎn)生的,編譯器在編譯源文件的時(shí)候,如果遇到了類似的宏,會(huì)自動(dòng)根據(jù)程序中表達(dá)式的內(nèi)容,生成一個(gè)字符串的宏。

這種方式的優(yōu)點(diǎn)是可以用統(tǒng)一的方法打印表達(dá)式的內(nèi)容,在程序的調(diào)試過(guò)程中可以方便直觀的看到轉(zhuǎn)換字符串之后的表達(dá)式。

具體的表達(dá)式的內(nèi)容是什么,有編譯器自動(dòng)寫入程序中,這樣使用相同的宏打印所有表達(dá)式的字符串。

//打印字符
#define?debugc(expr)?printf("?%s?=?%c\n",?#expr,?expr)
//打印浮點(diǎn)數(shù)
#define?debugf(expr)?printf("?%s?=?%f\n",?#expr,?expr)
//按照16進(jìn)制打印整數(shù)
#define?debugx(expr)?printf("?%s?=?0X%x\n",?#expr,?expr);
由于#expr本質(zhì)上市一個(gè)表示字符串的宏,因此在程序中也可以不適用%s打印它的內(nèi)容,而是可以將其直接與其它的字符串連接。

因此,上述宏可以等價(jià)以下形式:

//打印字符
#define?debugc(expr)?printf("?#expr?=?%c\n",?expr)
//打印浮點(diǎn)數(shù)
#define?debugf(expr)?printf("?#expr?=?%f\n",?expr)
//按照16進(jìn)制打印整數(shù)
#define?debugx(expr)?printf("?#expr?=?0X%x\n",?expr);
「總結(jié):」

#是C語(yǔ)言預(yù)處理階段的字符串化操作符,可將宏中的內(nèi)容轉(zhuǎn)換成字符串。

03.## 連接操作符

在gcc的編譯系統(tǒng)中,##是C語(yǔ)言中的連接操作符,可以在編譯的預(yù)處理階段實(shí)現(xiàn)字符串連接的操作。

「程序示例:」

#include?

#define?test(x)?test##x

void?test1(int?a)
{
????printf("test1?a?=?%d\n",?a);
}

void?test2(char?*s)
{
????printf("test2?s?=?%s\n",?s);
}

int?main(void)
{
????test(1)(100);

????test(2)("hello?world");
????
????return?0;
}
上述程序中,test(x)宏被定義為test##x, 他表示test字符串和x字符串的連接。

在程序的調(diào)試語(yǔ)句中,##常用的方式如下

#define?DEBUG(fmt,?args...)?printf(fmt,?##args)
替換的方式是將參數(shù)的兩個(gè)部分以##連接。##表示連接變量代表前面的參數(shù)列表。使用這種形式可以將宏的參數(shù)傳遞給一個(gè)參數(shù)。args…是宏的參數(shù),表示可變的參數(shù)列表,使用##args將其傳給printf函數(shù).

「總結(jié):」

##是C語(yǔ)言預(yù)處理階段的連接操作符,可實(shí)現(xiàn)宏參數(shù)的連接。

04.調(diào)試宏第一種形式

一種定義的方式:

#define?DEBUG(fmt,?args...)?????????????\
????{???????????????????????????????????\
????printf("file:%s?function:?%s?line:?%d?",?__FILE__,?__FUNCTION__,?__LINE__);\
????printf(fmt,?##args);????????????????\
????}

「程序示例:」

#include?

#define?DEBUG(fmt,?args...)?????????????\
????{???????????????????????????????????\
????printf("file:%s?function:?%s?line:?%d?",?__FILE__,?__FUNCTION__,?__LINE__);\
????printf(fmt,?##args);????????????????\
????}



int?main(void)
{
????int?a?=?100;
????int?b?=?200;

????char?*s?=?"hello?world";
????DEBUG("a?=?%d?b?=?%d\n",?a,?b);
????DEBUG("a?=?%x?b?=?%x\n",?a,?b);
????DEBUG("s?=?%s\n",?s);
????
????return?0;
}
「總結(jié):」

上面的DEBUG定義的方式是兩條語(yǔ)句的組合,不可能在產(chǎn)生返回值,因此不能使用它的返回值。

05.調(diào)試宏的第二種定義方式

調(diào)試宏的第二種定義方式

#define?DEBUG(fmt,?args...)?????????????\
????printf("file:%s?function:?%s?line:?%d?"fmt,?\
????__FILE__,?__FUNCTION__,?__LINE__,?##args)

程序示例

#include?

#define?DEBUG(fmt,?args...)?????????????\
????printf("file:%s?function:?%s?line:?%d?"fmt,?\
????__FILE__,?__FUNCTION__,?__LINE__,?##args)



int?main(void)
{
????int?a?=?100;
????int?b?=?200;

????char?*s?=?"hello?world";
????DEBUG("a?=?%d?b?=?%d\n",?a,?b);
????DEBUG("a?=?%x?b?=?%x\n",?a,?b);
????DEBUG("s?=?%s\n",?s);
????
????return?0;
}
「總結(jié):」

fmt必須是一個(gè)字符串,不能使用指針,只有這樣才可以實(shí)現(xiàn)字符串的功能。

06.對(duì)調(diào)試語(yǔ)句進(jìn)行分級(jí)審查

即使定義了調(diào)試的宏,在工程足夠大的情況下,也會(huì)導(dǎo)致在打開(kāi)宏開(kāi)關(guān)的時(shí)候在終端出現(xiàn)大量的信息。而無(wú)法區(qū)分哪些是有用的。

這個(gè)時(shí)候就要加入分級(jí)檢查機(jī)制,可以定義不同的調(diào)試級(jí)別,這樣就可以對(duì)不同重要程序和不同的模塊進(jìn)行區(qū)分,需要調(diào)試哪一個(gè)模塊就可以打開(kāi)那一個(gè)模塊的調(diào)試級(jí)別。

一般可以利用配置文件的方式顯示,其實(shí)Linux內(nèi)核也是這么做的,它把調(diào)試的等級(jí)分成了7個(gè)不同重要程度的級(jí)別,只有設(shè)定某個(gè)級(jí)別可以顯示,對(duì)應(yīng)的調(diào)試信息才會(huì)打印到終端上。

可以寫出一下配置文件

[debug]
debug_level=XXX_MODULE
解析配置文件使用標(biāo)準(zhǔn)的字符串操作庫(kù)函數(shù)就可以獲取XXX_MODULE這個(gè)數(shù)值。

int?show_debug(int?level)
{
????if?(level?==?XXX_MODULE)
????{
????????#define?DEBUG(fmt,?args...)?????????????\
????????printf("file:%s?function:?%s?line:?%d?"fmt,?\
????????__FILE__,?__FUNCTION__,?__LINE__,?##args)???????

????}
????else?if?(...)
????{
????????....
????}
}

07.條件編譯調(diào)試語(yǔ)句

在實(shí)際的開(kāi)發(fā)中,一般會(huì)維護(hù)兩種源程序,一種是帶有調(diào)試語(yǔ)句的調(diào)試版本程序,另外一種是不帶有調(diào)試語(yǔ)句的發(fā)布版本程序。

然后根據(jù)不同的條件編譯選項(xiàng),編譯出不同的調(diào)試版本和發(fā)布版本的程序。

在實(shí)現(xiàn)過(guò)程中,可以使用一個(gè)調(diào)試宏來(lái)控制調(diào)試語(yǔ)句的開(kāi)關(guān)。

#ifdef?USE_DEBUG
????????#define?DEBUG(fmt,?args...)?????????????\
????????printf("file:%s?function:?%s?line:?%d?"fmt,?\
????????__FILE__,?__FUNCTION__,?__LINE__,?##args)??

#else
??#define?DEBUG(fmt,?args...)

#endif
如果USE_DEBUG被定義,那么有調(diào)試信息,否則DEBUG就為空。

如果需要調(diào)試信息,就只需要在程序中更改一行就可以了。

#define?USE_DEBUG
#undef?USE_DEBUG
定義條件編譯的方式使用一個(gè)帶有值的宏

#if?USE_DEBUG
????????#define?DEBUG(fmt,?args...)?????????????\
????????printf("file:%s?function:?%s?line:?%d?"fmt,?\
????????__FILE__,?__FUNCTION__,?__LINE__,?##args)??

#else
??#define?DEBUG(fmt,?args...)

#endif
可以使用如下方式進(jìn)行條件編譯

#ifndef?USE_DEBUG
#define?USE_DEBUG?0
#endif

08.使用do…while的宏定義

使用宏定義可以將一些較為短小的功能封裝,方便使用。宏的形式和函數(shù)類似,但是可以節(jié)省函數(shù)跳轉(zhuǎn)的開(kāi)銷。

如何將一個(gè)語(yǔ)句封裝成一個(gè)宏,在程序中常常使用do…while(0)的形式。

#define?HELLO(str)?do?{?\
printf("hello:?%s\n",?str);?\
}while(0)

「程序示例:」

int?cond?=?1;
if?(cond)
????HELLO("true");
else
????HELLO("false");

09.代碼剖析

對(duì)于比較大的程序,可以借助一些工具來(lái)首先把需要優(yōu)化的點(diǎn)清理出來(lái)。接下來(lái)我們來(lái)看看在程序執(zhí)行過(guò)程中獲取數(shù)據(jù)并進(jìn)行分析的工具:代碼剖析程序。

「測(cè)試程序:」

#include?


#define?T?100000

void?call_one()
{
????int?count?=?T?*?1000;
????while(count--);
}

void?call_two()
{
????int?count?=?T?*?50;
????while(count--);
}

void?call_three()
{
????int?count?=?T?*?20;
????while(count--);
}


int?main(void)
{
????int?time?=?10;

????while(time--)
????{
????????call_one();
????????call_two();
????????call_three();
????}
????
????return?0;
}
編譯的時(shí)候加入-pg選項(xiàng):

deng@itcast:~/tmp$?gcc?-pg??test.c?-o?test
執(zhí)行完成后,在當(dāng)前文件中生成了一個(gè)gmon.out文件。

deng@itcast:~/tmp$?./test??
deng@itcast:~/tmp$?ls
gmon.out??test??test.c
deng@itcast:~/tmp$?
「使用gprof剖析主程序:」

deng@itcast:~/tmp$?gprof?test
Flat?profile:

Each?sample?counts?as?0.01?seconds.
??%???cumulative???self??????????????self?????total???????????
?time???seconds???seconds????calls??ms/call??ms/call??name????
?95.64??????1.61?????1.61???????10???160.68???160.68??call_one
??3.63??????1.67?????0.06???????10?????6.10?????6.10??call_two
??2.42??????1.71?????0.04???????10?????4.07?????4.07??call_three
其中主要的信息有兩個(gè),一個(gè)是每個(gè)函數(shù)執(zhí)行的時(shí)間占程序總時(shí)間的百分比,另外一個(gè)就是函數(shù)被調(diào)用的次數(shù)。通過(guò)這些信息,可以優(yōu)化核心程序的實(shí)現(xiàn)方式來(lái)提高效率。

當(dāng)然這個(gè)剖析程序由于它自身特性有一些限制,比較適用于運(yùn)行時(shí)間比較長(zhǎng)的程序,因?yàn)榻y(tǒng)計(jì)的時(shí)間是基于間隔計(jì)數(shù)這種機(jī)制,所以還需要考慮函數(shù)執(zhí)行的相對(duì)時(shí)間,如果程序執(zhí)行時(shí)間過(guò)短,那得到的信息是沒(méi)有任何參考意義的。

「將上訴程序時(shí)間縮短:」

#include?


#define?T?100

void?call_one()
{
????int?count?=?T?*?1000;
????while(count--);
}

void?call_two()
{
????int?count?=?T?*?50;
????while(count--);
}

void?call_three()
{
????int?count?=?T?*?20;
????while(count--);
}


int?main(void)
{
????int?time?=?10;

????while(time--)
????{
????????call_one();
????????call_two();
????????call_three();
????}
????
????return?0;
}
「剖析結(jié)果如下:」

deng@itcast:~/tmp$?gcc?-pg?test.c?-o?test
deng@itcast:~/tmp$?./test??
deng@itcast:~/tmp$?gprof?test
Flat?profile:

Each?sample?counts?as?0.01?seconds.
?no?time?accumulated

??%???cumulative???self??????????????self?????total???????????
?time???seconds???seconds????calls??Ts/call??Ts/call??name????
??0.00??????0.00?????0.00???????10?????0.00?????0.00??call_one
??0.00??????0.00?????0.00???????10?????0.00?????0.00??call_three
??0.00??????0.00?????0.00???????10?????0.00?????0.00??call_two
因此該剖析程序?qū)τ谠綇?fù)雜、執(zhí)行時(shí)間越長(zhǎng)的函數(shù)也適用。

那么是不是每個(gè)函數(shù)執(zhí)行的絕對(duì)時(shí)間越長(zhǎng),剖析顯示的時(shí)間就真的越長(zhǎng)呢?可以再看如下的例子

#include?


#define?T?100

void?call_one()
{
????int?count?=?T?*?1000;
????while(count--);
}

void?call_two()
{
????int?count?=?T?*?100000;
????while(count--);
}

void?call_three()
{
????int?count?=?T?*?20;
????while(count--);
}


int?main(void)
{
????int?time?=?10;

????while(time--)
????{
????????call_one();
????????call_two();
????????call_three();
????}
????
????return?0;
}
「剖析結(jié)果如下:」

deng@itcast:~/tmp$?gcc?-pg?test.c?-o?test
deng@itcast:~/tmp$?./test??
deng@itcast:~/tmp$?gprof?test
Flat?profile:

Each?sample?counts?as?0.01?seconds.
??%???cumulative???self??????????????self?????total???????????
?time???seconds???seconds????calls??ms/call??ms/call??name????
101.69??????0.15?????0.15???????10????15.25????15.25??call_two
??0.00??????0.15?????0.00???????10?????0.00?????0.00??call_one
??0.00??????0.15?????0.00???????10?????0.00?????0.00??call_three

「總結(jié):」

在使用gprof工具的時(shí)候,對(duì)于一個(gè)函數(shù)進(jìn)行g(shù)prof方式的剖析,實(shí)質(zhì)上的時(shí)間是指除去庫(kù)函數(shù)調(diào)用和系統(tǒng)調(diào)用之外,純碎應(yīng)用部分開(kāi)發(fā)的實(shí)際代碼運(yùn)行的時(shí)間,也就是說(shuō)time一項(xiàng)描述的時(shí)間值不包括庫(kù)函數(shù)printf、系統(tǒng)調(diào)用system等運(yùn)行的時(shí)間。

這些實(shí)用庫(kù)函數(shù)的程序雖然運(yùn)行的時(shí)候?qū)⒈茸畛醯某绦驅(qū)嵱酶嗟臅r(shí)間,但是對(duì)于剖析函數(shù)來(lái)說(shuō)并沒(méi)有影響。

10.附錄

嵌入式Linux上的C語(yǔ)言編程實(shí)踐

來(lái)源:https://blog.csdn.net/dengjin20104042056

本文來(lái)源網(wǎng)絡(luò),版權(quán)歸原作者所有。如涉及作品版權(quán)問(wèn)題,請(qǐng)聯(lián)系我進(jìn)行刪除。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉