一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

學(xué)習(xí)使用帶參宏,提高編程基礎(chǔ)(二)

 嵌入式大雜燴 2021-08-20

正念君

一位熱愛編程的程序員

往期資料  == 菜單欄下有更多資料

資源分享 | 嵌入式相關(guān)

資源分享 | 編程語言類

資源分享 | Linux相關(guān)資料

資源分享 | 數(shù)據(jù)結(jié)構(gòu)與算法

帶參宏實例分享

帶參宏在我們的嵌入式編程中使用得非常多,其定義如下:

#define 標識符(參數(shù)列表) 字符序列

其中參數(shù)列表中的參數(shù)之間用逗號分隔,字符序列中應(yīng)包含參數(shù)表中的參數(shù)。在定義帶參數(shù)的宏時,宏名標識符與左圓括號之間不允許有空白符,應(yīng)緊接在一起,否則變成了無參數(shù)的宏定義。

并且,字符序列與其每一個參數(shù)必須用括號擴起來,否則該宏定義可能會產(chǎn)生二義性。下面舉個簡單的例子,定義一個求平方的宏函數(shù):

#include <stdio.h>
#define SQUARE(a) a*a // 不嚴謹?shù)膶懛?/span>
int main(void)
{
  int x = 5;
  int res = 0;
  res = SQUARE(x+2);
  printf("res = %d\n", res);
  return 0;
}

輸出結(jié)果如下:

res變量的輸出結(jié)果為17,與我們期望的res = 49;相差甚遠!這就是因為我們不給字符序列中的宏參數(shù)加括號的原因,產(chǎn)生了歧義。程序生成可執(zhí)行程序之前的預(yù)處理過程中把SQUARE(x+2)替換成了x+2*x+2,因此當x=5時res的結(jié)果為17。我們可以使用命令gcc -E hello.c -o hello.i進行預(yù)處理,然后查看經(jīng)過預(yù)處理得到的文件hello.i的內(nèi)容,hello.i里的內(nèi)容如下:

hello.i里的內(nèi)容與我們上面分析的一致!關(guān)于C程序的編譯原理可查看往期筆記:【本質(zhì)】你知道C語言編譯的過程嗎?關(guān)于windows系統(tǒng)下使用gcc編譯器的方法可參考往期筆記:使用Notepad++來開發(fā)C程序

以上程序嚴謹?shù)那笃椒降暮旰瘮?shù)的定義如下:

#include <stdio.h>
#define SQUARE(a) ((a)*(a)) // 嚴謹?shù)淖龇?/span>
int main(void)
{
  int x = 5;
  int res = 0;
  res = SQUARE(x+2);
  printf("res = %d\n", res);
  return 0;
}

程序輸出結(jié)果如下:

可見,這才是我們要的正確結(jié)果。

帶參宏到底有多重要,看看TI的一些官方例程就知道,其把很多算法使用帶參宏封裝起來,用戶就可以很方便的使用。

 帶參宏—— clarke變換算法

帶參宏—— PI調(diào)節(jié)器算法

這些.h文件都使用宏來封裝各種算法

同樣,ST官方固件庫中也大量使用帶參宏:

可見帶參宏定義的重要性!除此之外,通過以上宏定義,可發(fā)現(xiàn)很多宏定義分行時,其行后都加上反斜杠 \ 進行分隔,這也是需要注意的細節(jié)。

帶參宏與函數(shù)的區(qū)別

查看以上帶參宏,我們發(fā)現(xiàn)帶參宏似乎與函數(shù)似乎長得很像,它們之間有什么區(qū)別和聯(lián)系呢?TI為什么要使用宏來對一些算法進行封裝呢,難道使用函數(shù)來封裝不可以嗎?答案是可以的:

TI也說了,使用者可以很方便地把這些算法宏轉(zhuǎn)換成一些函數(shù)。換句話說就是你可以使用宏定義,也可以使用函數(shù)。那么,什么時候封裝成宏定義比較好,什么時候封裝成函數(shù)比較好呢?

以下內(nèi)容參考文章:

http://blog.sina.com.cn/s/blog_861912cd0100tc94.html

下面,先看一下帶參宏與函數(shù)的一些區(qū)別,舉個例子,比較兩個數(shù)或者表達式大?。?/span>

(1)帶參宏的方式:

#define MAX(a,b) ((a)>(b)?(a):(b))

(2)函數(shù)封裝的方式:

int max(int a, int b)
{
  return (a > b ? a : b);
}

很顯然,我們不會選擇用函數(shù)來完成這個任務(wù),原因有兩個:

(1)首先,函數(shù)調(diào)用會帶來額外的開銷,它需要開辟一片棧空間,記錄返回地址,將形參壓棧,從函數(shù)返回還要釋放堆棧。這種開銷不僅會降低代碼效率,而且代碼量也會大大增加,而使用宏定義則在代碼規(guī)模和速度方面都比函數(shù)更勝一籌;

(2)其次,函數(shù)的參數(shù)必須被聲明為一種特定的類型,所以它只能在類型合適的表達式上使用,我們?nèi)绻容^兩個浮點型的大小,就不得不再寫一個專門針對浮點型的比較函數(shù)。反之,上面的那個宏定義可以用于整形、長整形、單浮點型、雙浮點型以及其他任何可以用“>”操作符比較值大小的類型,也就是說,宏是與類型無關(guān)的。

除此之外,宏與函數(shù)的不同點還有:宏是在預(yù)處理階段展開,占用的是編譯時間,函數(shù)實在程序運行時調(diào)用的,占用的是程序運行的時間;宏參數(shù)沒有類型說明,也沒有返回值的概念。

和使用函數(shù)相比,使用宏的不利之處在于每次使用宏時,一份宏定義代碼的拷貝都會插入到程序中。除非宏非常短,否則使用宏會大幅度增加程序的長度。

還有一些任務(wù)根本無法用函數(shù)實現(xiàn),但是用宏定義卻很好實現(xiàn)。比如參數(shù)類型沒法作為參數(shù)傳遞給函數(shù),但是可以把參數(shù)類型傳遞給帶參的宏。

看下面的例子:

#define MALLOC(n, type)\
 ?。?type *) malloc((n)* sizeof(type)))

利用這個宏,我們就可以為任何類型分配一段我們指定的空間大小,并返回指向這段空間的指針。我們可以觀察一下這個宏確切的工作過程:

int *ptr;
ptr = MALLOC(5, int);

將這宏展開以后的結(jié)果:

ptr = (int *)malloc((5) * sizeof(int));

這個例子是宏定義的經(jīng)典應(yīng)用之一,完成了函數(shù)不能完成的功能,但是宏定義也不能濫用,通常,如果相同的代碼需要出現(xiàn)在程序的幾個地方,更好的方法是把它實現(xiàn)為一個函數(shù)。

以上就是關(guān)于帶參宏的一些總結(jié),如有錯誤,歡迎指出!

ps:資料鏈接失效怎么辦?

    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    欧美一级内射一色桃子| 综合久综合久综合久久| 99热九九在线中文字幕| 国产福利一区二区三区四区| 中文字幕人妻综合一区二区| 欧美日韩精品一区免费| 午夜久久精品福利视频| 欧美综合色婷婷欧美激情| 91亚洲国产成人久久精品麻豆| 亚洲一区二区三区熟女少妇| 午夜直播免费福利平台| 欧美日韩一区二区综合| 欧美特色特黄一级大黄片| 在线观看视频日韩成人| 激情图日韩精品中文字幕| 国产女同精品一区二区| 久久精品亚洲精品国产欧美| 美国黑人一级黄色大片| 一本久道久久综合中文字幕| 亚洲国产欧美久久精品| 日韩在线视频精品视频| 好吊色免费在线观看视频| 亚洲欧美日本国产有色| 成人精品亚洲欧美日韩| 日本精品最新字幕视频播放| 欧美又大又黄刺激视频| 欧美成人免费夜夜黄啪啪| 日韩欧美黄色一级视频| 精品国产亚洲区久久露脸| 国产精品一区二区视频| 国产亚洲系列91精品| 免费在线播放一区二区| 偷自拍亚洲欧美一区二页| 国产又粗又猛又爽又黄| 日本亚洲精品在线观看| 亚洲婷婷开心色四房播播| 激情内射亚洲一区二区三区| 久久少妇诱惑免费视频| 欧美夫妻性生活一区二区| 中文字幕高清不卡一区| 国产在线视频好看不卡|