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

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

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

3天內不再提示

工程師避免這些誤區才能讓【宏】削鐵如泥

工程師 ? 來源:嵌入式資訊精選 ? 作者:嵌入式資訊精選 ? 2020-10-23 15:15 ? 次閱讀

語法錯誤當使用參數調用宏時,會將參數替換為宏主體,并與其他輸入文件一起檢查結果,以進行更多的宏調用,可以將部分來自宏主體和部分自變量的宏調用組合在一起。例如,

#define twice(x) (2*(x))#define call_with_1(x) x(1)call_with_1 (twice)//x=1 → twice(1) → (2*(1))

宏定義不必帶有括號,通過在宏主體中編寫不平衡的開放括號,可以創建一個從宏主體內部開始但在宏主體外部結束的宏調用。例如,

#define strange(file) fprintf (file, “%s %d”,…strange(stderr) p, 35) → fprintf (stderr, “%s %d”, p, 35)

組合宏調用的功能可能會很有用,但是在宏主體中使用不平衡的開放括號只會造成混淆,應該避免。

運算符優先級問題在大多數宏定義示例中,每次出現的宏參數名稱都帶有括號,并且另一對括號通常會包圍整個宏定義,這是編寫宏最好的方式。舉個例子

#define ceil_div(x, y) (x + y - 1) / y

假定其用法如下:

a = ceil_div(b&c,sizeof(int));

拓展開是

a =(b&c + sizeof(int)-1)/ sizeof(int);

這沒有達到我們的預期,C的運算符優先級規則使其等效于此,而我們想要的是:

a =(((b&c)+ sizeof(int)-1))/ sizeof(int);

如果我們將宏定義為

#define ceil_div(x,y)((x)+(y)-1)/(y)

可能導致另一種情況,sizeof ceil_div(1,2)是一個C表達式,可以計算ceil_div(1,2)類型的大小,它擴展為:

sizeof((1)+(2)-1)/(2)

這將采用整數的大小并將其除以2,而除法包含在內部的sizeof之外。所以整個宏定義的括號可防止此類問題。那么,下面是定義ceil_div的正確方法如下

#define ceil_div(x,y)((((x)+(y)-1)/(y))

吞噬分號通常需要定義一個擴展為復合語句的宏。例如,考慮以下宏,該宏跨空格字符前進一個指針(參數p表示在何處查找):

#define SKIP_SPACES(p, limit) \{ char *lim = (limit); \ while (p 《 lim) { \ if (*p++ != ‘ ’) { \ p--; break; }}}

該宏定義必須是單個邏輯行,嚴格來說,該調用擴展為復合語句,這是一個完整的語句,不需要用分號結束。

但是,由于它看起來像函數調用,因此,如果可以像使用函數調用一樣使用它,則可以最大程度地減少混亂,然后再寫一個分號,就像在SKIP_SPACES(p,lim)中一樣。

這可能會在else語句之前出問題,因為分號實際上是空語句。假設你寫

if (*p != 0) SKIP_SPACES (p, lim);else …

在if條件和else條件之間存在兩個語句(復合語句和null語句)使C代碼無效。

怎么解決?我們可以使用do…while語句更改宏SKIP_SPACES的定義以解決此問題。方法如下:

#define SKIP_SPACES(p, limit) \do { char *lim = (limit); \ while (p 《 lim) { \ if (*p++ != ‘ ’) { \ p--; break; }}} \while (0)

SKIP_SPACES (p, lim);擴展為

do {…} while (0);

這是一個陳述,循環僅執行一次,而且大多數編譯器不會為此生成任何額外的代碼。

重復調用我們常見的“最小”定義一個宏min,如下所示:

#define min(X, Y) ((X) 《 (Y) ? (X) : (Y))

當將此宏與包含副作用的參數一起使用時,如此處所示,

next = min(x + y,foo(z));

它擴展如下:

next = ((x + y) 《 (foo (z)) ? (x + y) : (foo (z)));

其中x + y替換了X,而foo(z)替換了Y。

函數foo出現在程序中的語句中僅使用一次,但是表達式foo(z)已兩次替換到宏擴展中。結果,執行該語句時可能會兩次調用foo,所以min是一個不安全的宏。

解決此問題的最佳方法是以僅計算一次foo(z)值的方式定義min。C語言沒有提供執行此操作的標準方法,但是可以使用GNU擴展來完成此操作,如下所示:

#define min(X, Y) \({ typeof (X) x_ = (X); \ typeof (Y) y_ = (Y); \ (x_ 《 y_) ? x_ : y_; })

“({{…})”符號產生一個復合表達式,它的值是其最后一條語句的值。

如果不使用GNU C擴展,唯一的解決方案是在使用宏min時要小心。例如計算foo(z)的值時,將其保存在變量中,然后在min中使用該變量:

//假設foo返回int類型#define min(X, Y) ((X) 《 (Y) ? (X) : (Y))…{ int tem = foo (z); next = min (x + y, tem);}

自引用宏自引用宏是其名稱出現在其定義中的宏。我們知道所有宏定義都將被重新掃描以查找更多要替換的宏,如果自引用被認為是宏的使用,它將產生無限大的擴展。

為防止這種情況,自引用不被視為宏調用。它原樣傳遞到預處理器輸出中。舉個例子

#define foo (4 + foo)

按照普通規則,其宏定義分析如下

對foo的每個引用都將擴展為(4 + foo);

然后將對其進行重新掃描,并將其擴展為(4 +(4 + foo));

以此類推,直到計算機內存耗盡。

自引用規則將這一過程縮短了一步,即(4 + foo),因此此宏定義可能會導致程序在引用foo的任何地方將foo的值加4。

閱讀程序的人看到foo是變量,就難以記得它也是宏,真的會坑爹的。它的一種常見有用用法是創建一個可擴展為其自身的宏。如果你寫

#define EPERM EPERM

然后宏EPERM擴展為EPERM。實際上,每當在運行文本中使用預處理器時,預處理器都會將其單獨保留。

如果宏x擴展為使用宏y,而y的擴展引用了宏x,則這是x的間接自引用。在這種情況下,x也不展開,舉個例子

#define x (4 + y)#define y (2 * x)

然后x和y擴展如下:

x→(4 + y) →(4 +(2 * x))y→(2 * x) →(2 *(4 + y))

當每個宏出現在另一個宏的定義中時,它們將被展開,但是當它間接出現在其自己的定義中時,則不會被展開。

參數預掃描處理宏參數在被替換為宏主體之前必須經過完全宏擴展,替換后,將再次掃描整個宏主體,包括替換的參數,以查找要擴展的宏。

如果參數包含任何宏調用,則它們將在第一次掃描時擴展,那么結果不包含任何宏調用,因此第二次掃描不會更改它。

如果按照給定的方式替換了參數,并且沒有進行預掃描,則剩余的單個掃描將找到相同的宏調用并產生相同的結果。

預掃描處理在以下三種特殊情況下有大的作用。

對宏的嵌套調用當宏的參數包含對該宏的調用時,就會發生對宏的嵌套調用,舉個例子。

如果f是期望一個參數的宏,則f(f(1))是對f的嵌套調用對。通過擴展f(1)并將其代入f的定義來進行所需的擴展。預掃描會導致發生預期的結果。

如果沒有預掃描,f(1)本身將被替換為參數,并且f的內部使用將在主掃描期間作為間接自引用出現,并且不會擴展。

調用其他可進行字符串化或連接的宏的宏如果參數是字符串化或串聯的,則不會進行預掃描。

如果要擴展宏,然后對其擴展進行字符串化或串聯,則可以通過使一個宏調用進行該字符串化或串聯的另一宏來實現。舉個例子

#define AFTERX(x) X_ ## x#define XAFTERX(x) AFTERX(x)#define TABLESIZE 1024#define BUFSIZE TABLESIZE

然后AFTERX(BUFSIZE)擴展為X_BUFSIZE,而XAFTERX(BUFSIZE)擴展為X_1024而不是X_TABLESIZE,預掃描始終會進行完整的擴展。

參數中使用的宏,其擴展名包含未屏蔽的逗號。這可能導致使用錯誤數量的參數調用在第二次掃描時擴展的宏。舉個例子

#define foo a,b#define bar(x) lose(x)#define lose(x) (1 + (x))

我們預期的結果是bar(foo)變成(1 +(foo)),然后變成(1 +(a,b))。

然而bar(foo)擴展為loss(a,b)會出錯,因為Los需要一個參數。在這種情況下,該問題可以通過使用相同的括號輕松解決,該括號應用于防止算術運算的錯誤嵌套:

#define foo (a,b)or#define bar(x) lose((x))

多余的一對括號可防止foo定義中的逗號被解釋為參數分隔符。

參數中的換行符類似函數的宏的調用可以擴展到許多邏輯行,但是在本實施方式中,整個擴展是一行完成的。

因此,由編譯器或調試器發出的行號是指調用在其上開始的行,這可能與包含導致問題的參數的行不同,例如:

#define ignore_second_arg(a,b,c) a; cignore_second_arg (foo (), ignored (), syntax error);

由Syntax error on tokens觸發的語法錯誤會導致錯誤消息引用第三行(ignore_second_arg行),即使有問題的代碼來自第五行。

責任編輯:haq

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

    關注

    3

    文章

    4328

    瀏覽量

    62575
  • 編譯器
    +關注

    關注

    1

    文章

    1624

    瀏覽量

    49109
  • 宏匯編器
    +關注

    關注

    0

    文章

    7

    瀏覽量

    8985
收藏 人收藏

    評論

    相關推薦

    工程師在電路設計中的八大誤區

    我們常常會發現,自己想當然的一些規則或道理往往會存在一些差錯。電子工程師在電路設計中也會有這樣的例子。下面是一位工程師總結的八大誤區點。
    發表于 03-16 17:04 ?1615次閱讀

    電子工程師之路

    ,不應該一直沉默寡言。假如你能正確的明白自己缺少什么條件,怎么去滿足這些條件,我想你基本就要成功了。本人不才,簡單的說下了。本人喜歡交工程師朋友。有愿意和哥們交朋友的還請留言。
    發表于 11-27 14:02

    工程師手記:FPGA學習的四大誤區

    工程師手記:FPGA學習的四大誤區
    發表于 08-17 23:47

    新手學習PADS的三個誤區

    很多新手經常糾結的一件事就是學習PADS是不是可以拿高薪,是不是可以成為一個工程師,其實這些都是很大的誤區誤區大致都是在以下幾種情況第一:我很熟練的掌握了PADS工具,其實PADS與
    發表于 07-30 17:10

    如何才能讓自己成為一名嵌入式開發工程師

    卻比比皆是。面對一個如此朝陽的行業,我們如何才能讓自己成為一名嵌入式開發工程師?成為一名優秀的嵌入式開發工程師有哪些要求?  我們都知道,嵌入式主要由硬件和軟件兩部分組成,硬件(微處理器硬件)是軟件
    發表于 11-08 07:40

    如何才能成為一個硬件工程師

    如何才能成為一個硬件工程師
    發表于 11-11 07:11

    如何才能讓自己成為一名優秀的嵌入式開發工程師

      在互聯網行業中,嵌入式技術后來居上,因為物聯網和人工智能的發展,嵌入式技術越來越值錢,學嵌入式的人也越來越多。面對一個如此朝陽的行業,我們如何才能讓自己成為一名優秀的嵌入式開發工程師?嵌入式入門
    發表于 12-17 06:46

    FPGA工程師需要具備哪些技能?

    ,需要具備一系列的技能,才能勝任日益復雜的設計工作。因此,本文將從設計思路、硬件語言、EDA工具、數字信號處理、通信協議、測試驗證等多個方面,探討FPGA工程師需要具備哪些技能。 一
    發表于 11-09 11:03

    工程師故事:怎樣才能成為優秀研發工程師呢?

    工程師故事:怎樣才能成為優秀研發工程師呢?其實三言兩語很難道盡工程師的成長心得。多年的工作中,我們體會比較深刻的有以下幾個方面:
    發表于 03-22 16:17 ?4153次閱讀

    工程師在電路設計中的八大誤區

    工程師在電路設計中的八大誤區,感興趣的小伙伴們可以瞧一瞧。
    發表于 05-12 10:28 ?0次下載

    什么樣的工程師才能被稱為資深Java工程師

    什么樣的工程師才能被稱為資深,又如何成為資深Java工程師呢?
    的頭像 發表于 08-05 16:15 ?3671次閱讀

    如何才能避免】的這七個誤區

    當使用參數調用時,會將參數替換為主體,并與其他輸入文件一起檢查結果,以進行更多的調用,可以將部分來自主體和部分自變量的調用組合在一
    的頭像 發表于 12-24 14:29 ?402次閱讀

    電子工程師設計電路的十四誤區資料下載

    電子發燒友網為你提供電子工程師設計電路的十四誤區資料下載的電子資料下載,更有其他相關的電路圖、源代碼、課件教程、中文資料、英文資料、參考設計、用戶指南、解決方案等資料,希望可以幫助到廣大的電子工程師們。
    發表于 04-01 08:50 ?22次下載
    電子<b class='flag-5'>工程師</b>設計電路的十四<b class='flag-5'>誤區</b>資料下載

    一位工程師總結的電路設計八大誤區點資料下載

    電子發燒友網為你提供一位工程師總結的電路設計八大誤區點資料下載的電子資料下載,更有其他相關的電路圖、源代碼、課件教程、中文資料、英文資料、參考設計、用戶指南、解決方案等資料,希望可以幫助到廣大的電子工程師們。
    發表于 04-21 08:52 ?9次下載
    一位<b class='flag-5'>工程師</b>總結的電路設計八大<b class='flag-5'>誤區</b>點資料下載
    主站蜘蛛池模板: 韩国无遮羞禁动漫在线观看96| 日韩视频中文在线一区| 国产精品99久久久久久宅男AV| 999精品影视在线观看| 午夜福利试看120秒体验区| 欧美黑大炮18p| 精品无码久久久久久久动漫 | 欧美美女一区二区三区| 精品99久久久久成人网站| 大肥女ass樱桃| freevideoshd| 征服丝袜旗袍人妻| 亚洲看片无码免费视频| 午夜在线播放免费人成无| 日韩欧美精品有码在线播放| 嫩草在线播放| 裸妇厨房风流在线观看| 久久精品国产亚洲精品2020| 国产亚洲精品久久孕妇呦呦你懂| 俄罗斯人与动ZOZ0| 边摸边吃奶边做下面视频| xxxx69中国| 哒哒哒影院在线观看免费高清 | 手机在线免费看毛片| 欧洲videosdesrxotv| 欧美亚洲韩日午夜| 日韩精品 中文字幕 有码| 三级黄色视屏| 天天狠狠色综合图片区| 日本久久中文字幕| 你的欲梦裸身在线播放| 久久综合视频网站| 狠狠干.in| 久久精品国产福利电影网| 九九夜夜妹子| 快播h动漫网站| 免费欧美大片| 日本熟妇多毛XXXXX视频| 日本不卡三卡四卡| 午夜视频在线观看国产| 亚洲伊人精品|