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

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

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

3天內不再提示

宏的高級用法

工程師 ? 來源:嵌入式軟件實戰派 ? 作者:嵌入式軟件實戰派 ? 2020-09-15 15:59 ? 次閱讀

對于條件/分支處理的程序設計,我們慣性地會選擇switch-case或者if-else,這也是C語言老師當初教的。以下,我們用一個播放器的例子來說明,要實現的功能如下:

收到用戶操作播放器命令請求,如“播放”、“暫停”等,程序要對命令作區分;

針對不同的命令請求,作相應的處理;

輸出必要的輔助信息

首先,將命令定義成enum類型:

enum { CMD_PLAY, CMD_PAUSE, CMD_STOP, CMD_PLAY_NEXT, CMD_PLAY_PREV, };

然后,用switch-case的分支處理:

switch(cmd) { case CMD_PLAY: // handle play command break; case CMD_PAUSE: // handle pause command break; case CMD_STOP: // handle stop command break; case CMD_PLAY_NEXT: // handle play next command break; case CMD_PLAY_PREV: // handle play previous command break; default: break; }

實際上,這也沒什么毛病。但是,時間長了,需求不斷變更,程序不斷迭代,這個switch-case會變得非常冗長而很難維護。你不相信?我曾經見到過》1000行的類似這樣的代碼。如果讓你接手維護這樣的代碼,你內心會不會狂奔著萬千***?

但是,我不敢更改這個祖傳的switch-case啊,那么小心翼翼地將這些命令處理封裝成函數。像這樣:

#define FUNC_IN() printf(“enter %s \r\n”, __FUNCTION__) void func_cmd_play(void* p) { FUNC_IN(); } void func_cmd_pause(void* p) { FUNC_IN(); } void func_cmd_stop(void* p) { FUNC_IN(); } void func_cmd_play_next(void* p) { FUNC_IN(); } void func_cmd_play_prev(void* p) { FUNC_IN(); } void player_cmd_handle(int cmd, void* p) { switch(cmd) { case CMD_PLAY: func_cmd_play(p); break; case CMD_PAUSE: func_cmd_pause(p); break; case CMD_STOP: func_cmd_stop(p); break; case CMD_PLAY_NEXT: func_cmd_play_next(p); break; case CMD_PLAY_PREV: func_cmd_play_prev(p); break; default: break; } }

后來,甲方還是不斷地更改需求,導致播放器的命令越來越多,幾十個上百個了……痛定思痛,我——要——改——革!!

解放switch-case/if-else

腦子里想來想去,度娘上翻來翻去,于是定義了個結構體:

typedef void(*pFunc)(void* p); typedef struct { tCmd cmd; pFunc func; }tPlayerStruct; tPlayerStruct player_cmd_func[] = { {CMD_PLAY, func_cmd_play) }, {CMD_PAUSE, func_cmd_pause) }, {CMD_STOP, func_cmd_stop) }, {CMD_PLAY_NEXT, func_cmd_play_next) }, {CMD_PLAY_PREV, func_cmd_play_prev) }, }; #define ARR_LEN(arr)sizeof(arr)/sizeof(arr[0]) void player_cmd_handle(int cmd, void* p) { for(int i = 0; i 《 ARR_LEN(player_cmd_func); i++) { if(player_cmd_func[i].cmd == cmd && NULL != player_cmd_func[i].func) { player_cmd_func[i].func(p); break; } } }

咦?好像代碼簡潔了不少哦,改完之后好有成就感。

身為追求卓越的程序員,我還是有點不滿意,可不可以不用for循環,直接使用player_cmd_func[cmd].func(p);,這樣還可以免去查詢的步驟,提高效率?

想法是好的,如果上面的程序不用for循環,有可能數組越界,還有如果有命令增加,順序下標不對應的問題。

之前,我在《C語言的奇技淫巧之五》中的第50條提到過這個方法,還立了個flag,我要用MACRO寫個更高效更好的代碼!

使用X-MACRO

你聽說過X-MACRO么?聽過沒聽過都沒關系,來,我們一起耍起來!

MACRO或者說宏定義(書上或者規范上一般講預處理)基本原因都很簡單,看看就很容易學會。看起來好像也是平淡無奇,似乎沒什么大作用。但是,你可別小看它,我們將其安上個“X”就很牛逼(不知道這個是啥傳統,對于某些函數的擴展,喜歡在其前面或后面加個“X”,然后這個函數比之前的函數功能強大很多,Windows里面的Api就有這案例)。

X-MACRO是一種可靠維護代碼或數據的并行列表的技術,其相應項必須以相同的順序出現。它們在至少某些列表無法通過索引組成的地方(例如編譯時)最有用。此類列表的示例尤其包括數組的初始化,枚舉常量和函數原型的聲明,語句序列和切換臂的生成等。X-MACRO的使用可以追溯到1960年代。它在現代C和C ++編程語言中仍然有用。

X-MACRO應用程序包括兩部分:

列表元素的定義。

擴展列表以生成聲明或語句的片段。

該列表由一個宏或頭文件(名為LIST)定義,該文件本身不生成任何代碼,而僅由一系列調用宏(通常稱為“ X”)與元素的數據組成。LIST的每個擴展都在X定義之前加上一個list元素的語法。LIST的調用會為列表中的每個元素擴展X。

好了,少扯淡,我們是實戰派,搞點有用的東西。

對于MACRO有幾個明顯的特征:

MACRO實際上就是做替換工作;

宏定義的替換工作是在編譯前進行的,即預編譯;

宏定義可以用undef取消,然后再重新反復定義。

我們就用這幾個特征把MACRO耍到牛X起來!

#define X(a,b)a int x = DEF_X(1,2); #undef DEF_X #define DEF_X(a,b)b int y = DEF_X(1,2);

從上面可以看到,這個x和y的值是不一樣的。

于是可以定義一個這樣的宏:

#define CMD_FUNC \ DEF_X(CMD_PLAY, func_cmd_play) \ DEF_X(CMD_PAUSE, func_cmd_pause) \ DEF_X(CMD_STOP, func_cmd_stop) \ DEF_X(CMD_PLAY_NEXT, func_cmd_play_next) \ DEF_X(CMD_PLAY_PREV, func_cmd_play_prev) \

CMD的enum可以這樣定義:

typedef enum { #define DEF_X(a,b) a, CMD_FUNC #undef DEF_X CMD_MAX }tCmd;

預編譯后,這實際上就是這樣的:

typedef enum { CMD_PLAY, CMD_PAUSE, CMD_STOP, CMD_PLAY_NEXT, CMD_PLAY_PREV, CMD_MAX }tCmd;

接著,我們按這種套路定義一個函數指針數組:

const pFunc player_funcs[] = { #define DEF_X(a,b) b, CMD_FUNC #undef DEF_X };

甚至,我們可以定義一個命令的字符串,以作打印信息用:

const char* str_cmd[] = { #define DEF_X(a,b) #a, CMD_FUNC #undef DEF_X };

只要這個DEF_X(a,b)里面的a和b是對應關系正確的,CMD_FUNC后面的元素順序是所謂了,這個比前面的結構體有天然優勢。這樣,我們就可以直接用下標開始操作了:

void player_cmd_handle(tCmd cmd, void* p) { if(cmd 《 CMD_MAX) { player_funcs[cmd](p); } else { printf(“Command(%d) invalid!\n”, cmd); } }

這不僅提高了效率,還不用擔心命令的順序問題。

這種X-MACRO的用法對分支結構,特別是消息命令的處理特別的方便高效。

以下附上該案例的完整測試源碼:

#include 《stdio.h》 #define FUNC_IN() printf(“enter %s \r\n”, __FUNCTION__) #define CMD_FUNC \ DEF_X(CMD_PLAY, func_cmd_play) \ DEF_X(CMD_PAUSE, func_cmd_pause) \ DEF_X(CMD_STOP, func_cmd_stop) \ DEF_X(CMD_PLAY_NEXT, func_cmd_play_next) \ DEF_X(CMD_PLAY_PREV, func_cmd_play_prev) \ typedef enum { #define DEF_X(a,b) a, CMD_FUNC #undef DEF_X CMD_MAX }tCmd; const char* str_cmd[] = { #define DEF_X(a,b) #a, CMD_FUNC #undef DEF_X }; typedef void(*pFunc)(void* p); void func_cmd_play(void* p) { FUNC_IN(); } void func_cmd_pause(void* p) { FUNC_IN(); } void func_cmd_stop(void* p) { FUNC_IN(); } void func_cmd_play_next(void* p) { FUNC_IN(); } void func_cmd_play_prev(void* p) { FUNC_IN(); } const pFunc player_funcs[] = { #define DEF_X(a,b) b, CMD_FUNC #undef DEF_X }; void player_cmd_handle(tCmd cmd, void* p) { if(cmd 《 CMD_MAX) { player_funcs[cmd](p); } else { printf(“Command(%d) invalid!\n”, cmd); } } int main(void) { player_cmd_handle(CMD_PAUSE, (void*)0); player_cmd_handle(100, (void*)0); return 0; }

留個作業題:

如何靈活地將一個結構體的內容系列化到一個數組中,以及如何將一個數組的內容解系列化到結構體中?

例如,將以下結構體s的內容copy到data中(別老想著memcopy哦):

typedef struct STRUCT_DATA { int a; char b; short c; }tStruct;tStruct s; unsigned char data[100];

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

    關注

    5087

    文章

    19145

    瀏覽量

    306135
  • 宏匯編器
    +關注

    關注

    0

    文章

    7

    瀏覽量

    8995
收藏 人收藏

    評論

    相關推薦

    常州市領導蒞臨微科技走訪調研

    近日,常州市市長周偉一行蒞臨江蘇微科技股份有限公司(以下簡稱微科技)新竹廠區走訪調研。
    的頭像 發表于 01-08 16:24 ?182次閱讀

    keil在Debug的高級用法

    第一節軟件說明Keil提供了包括C編譯器、匯編、鏈接器、庫管理和一個功能強大的仿真調試器等在內的完整開發方案,通過一個集成開發環境(μVision)將這些部分組合在一起。目前軟件對中文的支持不友好
    的頭像 發表于 12-26 21:01 ?191次閱讀
    keil在Debug的<b class='flag-5'>高級</b><b class='flag-5'>用法</b>

    景智駕總部落地衢州

    近日,景智駕衢州總部落地儀式在南孔圣地衢州東方橋庵里大酒店盛大舉行!衢州智造新城黨工委副書記、管委會常務副主任巫建民與景智駕創始人及CEO劉飛龍博士共同為落地儀式剪彩。
    的頭像 發表于 12-24 17:10 ?380次閱讀

    DAC7562的CLR引腳怎么用法?可以懸空嗎?

    DAC7562的CLR引腳怎么用法?可以懸空嗎?能不能詳細解釋一下?謝謝
    發表于 12-17 08:16

    PCB高級EMC設計

    PCB高級EMC設計 ?
    的頭像 發表于 11-16 11:28 ?1513次閱讀
    PCB<b class='flag-5'>高級</b>EMC設計

    Linux lsof命令的基本用法

    在 linux 系統中,一切皆文件。通過文件不僅僅可以訪問常規數據,還可以訪問網絡連接和硬件。所以 lsof 命令不僅可以查看進程打開的文件、目錄,還可以查看進程監聽的端口等 socket 相關的信息。本文將介紹 lsof 命令的基本用法,本文中 demo 的演示環境為 ubuntu 18.04。
    的頭像 發表于 10-23 11:52 ?324次閱讀
    Linux lsof命令的基本<b class='flag-5'>用法</b>

    SV中define定義的用法

    SV中使用預處理指令`define來定義可以用來創建文本替換。根據場景不同,`define主要用來定義常量、簡化復雜的表達式或代碼段以及提高代碼的可移植性。其基本語法為:
    的頭像 發表于 10-21 14:22 ?649次閱讀

    安達發|APS高級排程高級物料需求計劃

    APS高級排程高級物料需求計劃是在制造業中非常重要的概念。它們分別涉及到生產計劃和物料管理,對于提高生產效率、降低成本和滿足客戶需求具有重要意義。下面我將詳細介紹這兩個概念及其在實際生產
    的頭像 發表于 09-25 17:49 ?333次閱讀
    安達發|APS<b class='flag-5'>高級</b>排程<b class='flag-5'>高級</b>物料需求計劃

    Sn74hc245具體的用法是什么?

    Sn74hc245是緩沖器,但是具體的用法不會
    發表于 09-10 07:32

    行業領導蒞臨景智駕考察交流

    近日,中國人才研究會汽車人才專業委員會理事長 朱明榮先生、同濟科技園常務副主任榮文偉先生一行蒞臨景智駕上海嘉定技術中心進行考察交流。 在深入了解景智駕公司發展情況后,各位領導對景智駕目前情況及未來發展給予了高度評價,并就
    的頭像 發表于 09-03 09:37 ?475次閱讀

    科技擬收購APCB 100%股權

    科技近期發布重要公告,宣布其計劃通過全資子公司新加坡勝及PSL,以不超過2.787億元人民幣的現金,全面收購APCB Electronics(Thailand)Co.,Ltd.(簡稱APCB)的100%股權。此次收購標志著勝
    的頭像 發表于 08-12 15:06 ?576次閱讀

    鴻蒙Ability Kit(程序框架服務)【UIAbility組件基本用法

    UIAbility組件的基本用法包括:指定UIAbility的啟動頁面以及獲取UIAbility的上下文[UIAbilityContext]。
    的頭像 發表于 06-06 11:02 ?504次閱讀
    鴻蒙Ability Kit(程序框架服務)【UIAbility組件基本<b class='flag-5'>用法</b>】

    鑫科技即將掛牌上市

    浙江鑫科技股份有限公司(以下簡稱“鑫科技”)成功獲得證監會的批文,即將掛牌上市,這標志著鑫科技將成為資本市場鍛造鋁合金車輪第一股,迎來產業經營和資本運營雙輪驅動的全新發展階段。
    的頭像 發表于 03-11 15:30 ?796次閱讀

    AWTK 開源串口屏開發(10) - 告警信息的高級用法

    信息的顯示和管理。本文介紹告警信息的兩種高級用法:查詢告警信息。如果告警信息比較多,我們需要通過查詢,來快速找到我們想要的告警信息。查看告警信息的詳情。如果某條告警
    的頭像 發表于 02-24 08:23 ?335次閱讀
    AWTK 開源串口屏開發(10) - 告警信息的<b class='flag-5'>高級</b><b class='flag-5'>用法</b>

    法拉電容放電保護原理是什么?如何正常使用法拉電容?

    法拉電容放電保護原理是什么?如何正常使用法拉電容? 法拉電容放電保護原理是指通過合理的設計和配置,保護法拉電容在放電過程中不受損壞的一種技術手段。法拉電容是一種具有高能量密度和長壽命的電容器
    的頭像 發表于 02-02 11:34 ?1987次閱讀
    主站蜘蛛池模板: 国产精品人妻午夜福利| 亞洲人妻AV無碼在線視頻| 国产精品免费一区二区三区四区| 亚洲免费观看| 女人精69xxxxx| 黄 色 网 站 免 费 涩涩屋| yy8090理论三级在线看| 亚洲伊人色| 四虎成人影院| 欧美性xxx免费看片| 久久99re66热这里只有精品| 国产成人免费在线观看| 99热在线免费播放| 在线视频a| 亚洲精品中文字幕一二三四区 | 精品久久久久久无码人妻国产馆| 成人免费一区二区无码视频 | 日本亚洲电影| 男宿舍里的呻吟h| 快播官方网站| 精品一区二区三区色花堂| 国产精品日本欧美一区二区| 菠萝菠萝蜜免费播放高清| 9797在线看片亚洲精品| 伊人久久综合影院首页| 亚洲欧美一区二区三区久久| 亚洲AV无码偷拍在线观看| 天堂视频在线观看免费完整版| 樱花草在线影视WWW日本动漫| 麻豆国产精品AV色拍综合| 国产精品亚洲二线在线播放| 99 久久99久久精品免观看| 亚洲国产在线视频精品| 日本VA在线视频播放| 空姐内射出白浆10p| 国产欧美日韩网站| 扒开胸罩揉她的乳尖视频| 在线精品国精品国产不卡| 午夜天堂一区人妻| 热思思| 一个人高清在线观看日本免费|