色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

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

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

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

關(guān)于嵌入式Linux調(diào)試相關(guān)的宏

STM32嵌入式開發(fā) ? 來源:STM32嵌入式開發(fā) ? 作者:STM32嵌入式開發(fā) ? 2022-07-06 16:29 ? 次閱讀

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

Linux使用gcc編譯程序的時候,對于調(diào)試的語句還具有一些特殊的語法。gcc編譯的過程中,會生成一些宏,可以使用這些宏分別打印當前源文件的信息,主要內(nèi)容是當前的文件、當前運行的函數(shù)和當前的程序行。

具體宏如下:

__FILE__  當前程序源文件 (char*)__FUNCTION__  當前運行的函數(shù) (char*)__LINE__  當前的函數(shù)行 (int)

這些宏不是程序代碼定義的,而是有編譯器產(chǎn)生的。這些信息都是在編譯器處理文件的時候動態(tài)產(chǎn)生的。

測試示例:

#include 
int main(void){    printf("file: %s
", __FILE__);    printf("function: %s
", __FUNCTION__);    printf("line: %d
", __LINE__);
    return 0;}

02.# 字符串化操作符

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

程序示例:

#include 
#define DPRINT(expr) printf("
%s = %d ", #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ù)(即表達式的內(nèi)容),生成一個字符串。該過程同樣是有編譯器產(chǎn)生的,編譯器在編譯源文件的時候,如果遇到了類似的宏,會自動根據(jù)程序中表達式的內(nèi)容,生成一個字符串的宏。

這種方式的優(yōu)點是可以用統(tǒng)一的方法打印表達式的內(nèi)容,在程序的調(diào)試過程中可以方便直觀的看到轉(zhuǎn)換字符串之后的表達式。具體的表達式的內(nèi)容是什么,有編譯器自動寫入程序中,這樣使用相同的宏打印所有表達式的字符串。

//打印字符#define debugc(expr) printf(" %s = %c
", #expr, expr)//打印浮點數(shù)#define debugf(expr) printf(" %s = %f
", #expr, expr)//按照16進制打印整數(shù)#define debugx(expr) printf(" %s = 0X%x
", #expr, expr);

由于#expr本質(zhì)上市一個表示字符串的宏,因此在程序中也可以不適用%s打印它的內(nèi)容,而是可以將其直接與其它的字符串連接。因此,上述宏可以等價以下形式:

//打印字符#define debugc(expr) printf(" #expr = %c
", expr)//打印浮點數(shù)#define debugf(expr) printf(" #expr = %f
", expr)//按照16進制打印整數(shù)#define debugx(expr) printf(" #expr = 0X%x
", expr);

總結(jié):

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

03.## 連接操作符

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

程序示例:

#include 
#define test(x) test##x
void test1(int a){    printf("test1 a = %d
", a);}
void test2(char *s){    printf("test2 s = %s
", s);}
int main(void){    test(1)(100);
    test(2)("hello world");        return 0;}

上述程序中,test(x)宏被定義為test##x, 他表示test字符串和x字符串的連接。

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

#define DEBUG(fmt, args...) printf(fmt, ##args)

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

總結(jié):

##是C語言預處理階段的連接操作符,可實現(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
", a, b);    DEBUG("a = %x b = %x
", a, b);    DEBUG("s = %s
", s);        return 0;}

總結(jié):

上面的DEBUG定義的方式是兩條語句的組合,不可能在產(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
", a, b);    DEBUG("a = %x b = %x
", a, b);    DEBUG("s = %s
", s);        return 0;}

總結(jié):

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

06.對調(diào)試語句進行分級審查

即使定義了調(diào)試的宏,在工程足夠大的情況下,也會導致在打開宏開關(guān)的時候在終端出現(xiàn)大量的信息。而無法區(qū)分哪些是有用的。這個時候就要加入分級檢查機制,可以定義不同的調(diào)試級別,這樣就可以對不同重要程序和不同的模塊進行區(qū)分,需要調(diào)試哪一個模塊就可以打開那一個模塊的調(diào)試級別。

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

可以寫出一下配置文件

[debug]debug_level=XXX_MODULE

解析配置文件使用標準的字符串操作庫函數(shù)就可以獲取XXX_MODULE這個數(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)試語句

在實際的開發(fā)中,一般會維護兩種源程序,一種是帶有調(diào)試語句的調(diào)試版本程序,另外一種是不帶有調(diào)試語句的發(fā)布版本程序。然后根據(jù)不同的條件編譯選項,編譯出不同的調(diào)試版本和發(fā)布版本的程序。

在實現(xiàn)過程中,可以使用一個調(diào)試宏來控制調(diào)試語句的開關(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

定義條件編譯的方式使用一個帶有值的宏

#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

可以使用如下方式進行條件編譯

#ifndef USE_DEBUG#define USE_DEBUG 0#endif

08.使用do…while的宏定義

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

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

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

程序示例:

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

09.代碼剖析

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

測試程序:

#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;}

編譯的時候加入-pg選項:

deng@itcast:~/tmp$ gcc -pg  test.c -o test

執(zhí)行完成后,在當前文件中生成了一個gmon.out文件。

deng@itcast:~/tmp$ ./test  deng@itcast:~/tmp$ lsgmon.out  test  test.cdeng@itcast:~/tmp$

使用gprof剖析主程序:


deng@itcast:~/tmp$ gprof testFlat 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_two2.421.710.04104.074.07call_three

其中主要的信息有兩個,一個是每個函數(shù)執(zhí)行的時間占程序總時間的百分比,另外一個就是函數(shù)被調(diào)用的次數(shù)。通過這些信息,可以優(yōu)化核心程序的實現(xiàn)方式來提高效率。

當然這個剖析程序由于它自身特性有一些限制,比較適用于運行時間比較長的程序,因為統(tǒng)計的時間是基于間隔計數(shù)這種機制,所以還需要考慮函數(shù)執(zhí)行的相對時間,如果程序執(zhí)行時間過短,那得到的信息是沒有任何參考意義的。

將上述程序時間縮短:

#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 testdeng@itcast:~/tmp$ ./test  deng@itcast:~/tmp$ gprof testFlat 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_three0.000.000.00100.000.00call_two

因此該剖析程序?qū)τ谠綇碗s、執(zhí)行時間越長的函數(shù)也適用。

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

#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 testdeng@itcast:~/tmp$ ./test  deng@itcast:~/tmp$ gprof testFlat 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_one0.000.150.00100.000.00call_three

總結(jié):

在使用gprof工具的時候,對于一個函數(shù)進行g(shù)prof方式的剖析,實質(zhì)上的時間是指除去庫函數(shù)調(diào)用和系統(tǒng)調(diào)用之外,純碎應用部分開發(fā)的實際代碼運行的時間,也就是說time一項描述的時間值不包括庫函數(shù)printf、系統(tǒng)調(diào)用system等運行的時間。這些實用庫函數(shù)的程序雖然運行的時候?qū)⒈茸畛醯某绦驅(qū)嵱酶嗟臅r間,但是對于剖析函數(shù)來說并沒有影響。

原文標題:嵌入式Linux C語言程序調(diào)試和宏使用技巧

文章出處:【微信公眾號:STM32嵌入式開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

審核編輯:彭靜

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

    關(guān)注

    5087

    文章

    19145

    瀏覽量

    306122
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11320

    瀏覽量

    209845
  • 編譯程序
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    4142

原文標題:嵌入式Linux C語言程序調(diào)試和宏使用技巧

文章出處:【微信號:c-stm32,微信公眾號:STM32嵌入式開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    嵌入式linux學習書籍匯總

      在總結(jié)這些嵌入式linux學習書籍之前,我在各個linux學習討論群,都能看到許多新手在問關(guān)于嵌入式
    發(fā)表于 06-08 08:31

    嵌入式Linux編譯調(diào)試

    嵌入式Linux編譯調(diào)試】VisualStdio+VisualGDB在嵌入式Linux開發(fā)中,常見的方式是通過sourceinsight編
    發(fā)表于 11-04 09:04

    嵌入式驅(qū)動開發(fā)中調(diào)試的方法是什么

    嵌入式驅(qū)動開發(fā)中調(diào)試的方法是什么
    發(fā)表于 12-24 06:55

    嵌入式Linux嵌入式Linux開發(fā)環(huán)境

    嵌入式Linux開發(fā) 圖1是一個典型的嵌入式Linux開發(fā)環(huán)境它包括主機工作站或者PC 支持GDB的調(diào)試工具BDI2000 目標板和網(wǎng)絡.
    發(fā)表于 09-10 10:22 ?119次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>和<b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>開發(fā)環(huán)境

    嵌入式Linux開發(fā)基礎(chǔ)知識

     嵌入式系統(tǒng)開發(fā)模式嵌入式Linux系統(tǒng)的構(gòu)成主要任務與流程利用Skyeye仿真開發(fā)板開發(fā)板使用嵌入式應用程序開發(fā)與調(diào)試
    發(fā)表于 09-10 11:07 ?39次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>開發(fā)基礎(chǔ)知識

    嵌入式Linux

    嵌入式Linux隨著Linux的迅速發(fā)展,嵌入式Linux現(xiàn)在已經(jīng)有許多的版本,包括強實時的嵌入式
    發(fā)表于 06-17 00:36 ?948次閱讀

    嵌入式LINUX開發(fā)基礎(chǔ)知識

    嵌入式LINUX簡介,嵌入式LINUX開發(fā)平臺簡介,嵌入式LINUX開發(fā)流程,建立
    發(fā)表于 07-31 21:34 ?261次下載

    嵌入式LINUX系統(tǒng)內(nèi)核和內(nèi)核模塊調(diào)試

    嵌入式LINUX系統(tǒng)內(nèi)核和內(nèi)核模塊調(diào)試(嵌入式開發(fā)和硬件開發(fā))-嵌入式LINUX系統(tǒng)內(nèi)核和內(nèi)核模
    發(fā)表于 07-30 13:55 ?10次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>LINUX</b>系統(tǒng)內(nèi)核和內(nèi)核模塊<b class='flag-5'>調(diào)試</b>

    嵌入式linux開發(fā)工具總結(jié)

    1.嵌入式linux開發(fā)工具-編譯器gcc(靜態(tài)庫 動態(tài)庫的制作)可以制作庫 庫的使用2.嵌入式linux開發(fā)工具-調(diào)試器gdb(
    發(fā)表于 11-01 16:32 ?12次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>linux</b>開發(fā)工具總結(jié)

    嵌入式Linux的Qt

    嵌入式Linux的Qt嵌入式Linux的Qt配置特定設備嵌入式Linux設備的平臺插件EGLFS
    發(fā)表于 11-01 17:06 ?3次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>的Qt

    嵌入式linux報警,嵌入式Linux下LED報警燈驅(qū)動設計及編程.doc

    設計及編程一.實驗目的理解驅(qū)動本質(zhì),掌握嵌入式Linux系統(tǒng)下驅(qū)動開發(fā)相關(guān)知識,包括端口寄存器訪問、接口函數(shù)編寫、和文件系統(tǒng)掛接、注冊及相關(guān)應用編程等知識點。二.實驗內(nèi)容實驗5.1
    發(fā)表于 11-01 17:21 ?6次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>linux</b>報警,<b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>下LED報警燈驅(qū)動設計及編程.doc

    嵌入式Linux編譯調(diào)試---1---】VisualStdio+VisualGDB

    嵌入式Linux編譯調(diào)試】VisualStdio+VisualGDB 在嵌入式Linux開發(fā)中,常見的方式是通過sourceinsight
    發(fā)表于 11-01 17:38 ?8次下載
    【<b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>編譯<b class='flag-5'>調(diào)試</b>---1---】VisualStdio+VisualGDB

    嵌入式Linux(基礎(chǔ)篇)】從標準Linux嵌入式Linux + 嵌入式Linux知識架構(gòu)

    主要介紹了GNU/Linux的誕生,標準Linux是如何應用在嵌入式系統(tǒng)中的,最后講述了嵌入式Linux知識架構(gòu)。
    發(fā)表于 11-02 09:51 ?34次下載
    【<b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>(基礎(chǔ)篇)】從標準<b class='flag-5'>Linux</b>到<b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b> + <b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>知識架構(gòu)

    嵌入式Linux network

    文章目錄前言網(wǎng)絡通信簡介服務器程序客戶端程序運行微信公眾號前言這是前篇:嵌入式Linux i.MX開發(fā)板嵌入式Linux NFS嵌入式
    發(fā)表于 11-02 10:51 ?15次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b> network

    嵌入式Linux路線

    嵌入式linux開發(fā)環(huán)境搭建、嵌入式linux開發(fā)模型、linux內(nèi)核移植和文件系統(tǒng)、嵌入式
    發(fā)表于 11-02 11:51 ?18次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>路線
    主站蜘蛛池模板: 亚洲专区中文字幕视频专区| 久久黄色小视频| 偷窥自拍性综合图区| 久久亚洲精品无码A片大香大香| 99久久国产综合精品国| 亚洲福利区| 日本三级黄色大片| 久久久性色精品国产免费观看 | 亚洲日韩在线天堂一| 全免费午夜一级毛片| 久久视频这里只精品99热在线观看 | 日产亚洲一区二区三区| 久久国产乱子伦精品免费不卡| 国产97视频在线观看| 99久久99久久精品免费看子| 亚洲欧洲精品成人久久曰影片| 色丁香婷婷综合缴情综| 嗯好舒服嗯好大好猛好爽| 精品视频中文字幕| 国产人妻人伦精品59HHH| 成人午夜精品无码区久久漫画日本 | 黄色精品视频| 国产成人在线免费观看| qvod在线观看| 99精品欧美一区二区三区美图| 亚洲视频在线免费看| 亚洲 欧美 另类 中文 在线| 丝袜足控免费网站xx91| 日韩在线中文字幕无码| 欧美夜夜噜2017最新| 嫩草视频在线观看免费| 美女被撕开胸罩狂揉大乳| 久久人妻少妇嫩草AV无码| 黑色丝袜在线观看| 国家产午夜精品无人区| 国产亚洲中文字幕视频| 国产欧美一区二区三区免费| 国产精品人妻无码77777| 国产扒开美女双腿屁股流白浆| 动漫美女人物被黄漫在线看| 大地影院日本韩国电影免费观看|