新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 單片機(jī)C語言中define的妙用

單片機(jī)C語言中define的妙用

作者: 時(shí)間:2016-11-29 來源:網(wǎng)絡(luò) 收藏
單片機(jī)C語言define的妙用

最近一款產(chǎn)品調(diào)試時(shí)發(fā)現(xiàn)了問題,在一起檢查一個(gè)小伙伴的C程序。問題不大,但暴露了一點(diǎn)問題。
比如:PORTB=0x23; //他的意思是把第5和第2位置1
可是你能一下子看出來第5和第2位置1嗎?其實(shí)應(yīng)該是0x24,他并沒有發(fā)現(xiàn)這個(gè)錯(cuò)誤,算錯(cuò)了,所以正確的是:
PORTB=0x23;
其實(shí),我們完全可以避免這個(gè)錯(cuò)誤。
打開我們編譯器自帶的頭文件,比如AVR Tiny13頭文件中有如下語句:
# define PB5 5
# define PB4 4
# define PB3 3
# define PB2 2
# define PB1 1
# define PB0 0

看似沒什么用,其實(shí)大有用處。
PORTB=0x24;就可以寫為:
PORTB=(1<這樣,是不是一下子就能看清誰跟誰了?也方便別人閱讀。

define的妙用遠(yuǎn)不止此,但基本的用法簡(jiǎn)單,要靈活運(yùn)用,才行。
下面是摘抄自網(wǎng)上的define用法,希望你能掌握并運(yùn)用。


#define用法
1.簡(jiǎn)單的define定義

#define MAXTIME 1000

一個(gè)簡(jiǎn)單的MAXTIME就定義好了,它代表1000,如果在程序里面寫

if(i

編譯器在處理這個(gè)代碼之前會(huì)對(duì)MAXTIME進(jìn)行處理替換為1000。

這樣的定義看起來類似于普通的常量定義CONST,但也有著不同,因?yàn)閐efine的定義更像是簡(jiǎn)單的文本替換,而不是作為一個(gè)量來使用,這個(gè)問題在下面反映的尤為突出。

2.define的“函數(shù)定義”
define可以像函數(shù)那樣接受一些參數(shù),如下

#define max(x,y) (x)>(y)?(x):(y);

這個(gè)定義就將返回兩個(gè)數(shù)中較大的那個(gè),看到了嗎?因?yàn)檫@個(gè)“函數(shù)”沒有類型檢查,就好像一個(gè)函數(shù)模板似的,當(dāng)然,它絕對(duì)沒有模板那么安全就是了。可以作為一個(gè)簡(jiǎn)單的模板來使用而已。

但是這樣做的話存在隱患,例子如下:
#define Add(a,b) a+b;
在一般使用的時(shí)候是沒有問題的,但是如果遇到如:c * Add(a,b) * d的時(shí)候就會(huì)出現(xiàn)問題,代數(shù)式的本意是a+b然后去和c,d相乘,但是因?yàn)槭褂昧薲efine(它只是一個(gè)簡(jiǎn)單的替換),所以式子實(shí)際上變成了
c*a + b*d

另外舉一個(gè)例子:
#define pin (int*);
pin a,b;
本意是a和b都是int型指針,但是實(shí)際上變成int* a,b;
a是int型指針,而b是int型變量。
這是應(yīng)該使用typedef來代替define,這樣a和b就都是int型指針了。

所以我們?cè)诙x的時(shí)候,養(yǎng)成一個(gè)良好的習(xí)慣,建議所有的層次都要加括號(hào)。

3.宏的單行定義

#define A(x) T_##x
#define B(x) #@x

#define C(x) #x
我們假設(shè):x=1,則有:
A(1)------〉T_1
B(1)------〉1
C(1)------〉"1"

(這里參考了 hustli的文章)

4.define的多行定義

define可以替代多行的代碼,例如MFC中的宏定義(非常的經(jīng)典,雖然讓人看了惡心)

#define MACRO(arg1, arg2) do { /
/
stmt1; /
stmt2; /
/
} while(0)
關(guān)鍵是要在每一個(gè)換行的時(shí)候加上一個(gè)"/"


5.在大規(guī)模的開發(fā)過程中,特別是跨平臺(tái)和系統(tǒng)的軟件里,define 最重要的功能是條件編譯。

就是:
#ifdef WINDOWS
......
......
#endif
#ifdef LINUX
......
......
#endif

可以在編譯的時(shí)候通過#define設(shè)置編譯環(huán)境

6.如何定義宏、取消宏

//定義宏
#define [MacroName] [MacroValue]
//取消宏
#undef [MacroName]
普通宏
#define PI (3.1415926)

帶參數(shù)的宏
#define max(a,b) ((a)>(b)? (a),(b))
關(guān)鍵是十分容易產(chǎn)生錯(cuò)誤,包括機(jī)器和人理解上的差異等等。

7.條件編譯

#ifdef XXX…(#else)…#endif
例如 #ifdef DV22_AUX_INPUT
#define AUX_MODE 3
#else
#define AUY_MODE 3
#endif
#ifndef XXX …(#else) …#endif

8.頭文件(.h)可以被頭文件或C文件包含

重復(fù)包含(重復(fù)定義)
由于頭文件包含可以嵌套,那么C文件就有可能包含多次同一個(gè)頭文件,就可能出現(xiàn)重復(fù)定義的問題的。
通過條件編譯開關(guān)來避免重復(fù)包含(重復(fù)定義)
例如
#ifndef __headerfileXXX__
#define __headerfileXXX__

文件內(nèi)容

#endif
9. #define中的#、## && #@

前些一段時(shí)間在看WinCE的Code時(shí)發(fā)現(xiàn)在宏定義中有用到##,如下所示

#define GPEBLT_FUNCNAME(basename) (SCODE (GPE::*)(struct GPEBltParms*))&GPE::##basename

在#define中,標(biāo)準(zhǔn)只定義了#和##兩種操作。#用來把參數(shù)轉(zhuǎn)換成字符串,##則用來連接兩個(gè)前后兩個(gè)參數(shù),把它們變成一個(gè)字符串。

1#define ToString(a) #a

2ToString( A b Cd ); //A b Cd

3ToString( A/n b Cd ); //A

4 // b Cd

5ToString( A/ n b Cd ); //A n b Cd

6

7

8#define ConCat(x, y) x ## y

9ConCat( "ABC", "DEF" );

10ConCat( 123, 4);

11ConCat( 123.0, 5);

12//=================================

13// Cat( 123.0, 5.5);

14// Cat( a, b );

15// Cat( "ABC", d );

16// Cat( a, 1234 );

17// Cat( "ABC", 1234 );

18//===== above cant compile =======

19

20

另外,在網(wǎng)上搜到還有一種用法:#@,把參數(shù)轉(zhuǎn)換成字符



1#define ToChar(a) #@a

2ToChar(a); // a

3ToChar(ab); // b

4ToChar(abc); // c

5ToChar(abcd); // d

6//ToChar(abcde); // too many characters in constant

7ToChar(1.); // .

這個(gè)沒在標(biāo)準(zhǔn)上看到。上述測(cè)試是在VS studio環(huán)境下做的。不知道GCC中是否有同樣的用法。



最后附上#define和typedef的區(qū)別

1) #define是預(yù)處理指令,在編譯預(yù)處理時(shí)進(jìn)行簡(jiǎn)單的替換,不作正確性檢查,不關(guān)含義是否正確照樣帶入,只有在編譯已被展開的源程序時(shí)才會(huì)發(fā)現(xiàn)可能的錯(cuò)誤并報(bào)錯(cuò)。例如:
#define PI 3.1415926
程序中的:area=PI*r*r 會(huì)替換為3.1415926*r*r
如果你把#define語句中的數(shù)字9寫成字母g 預(yù)處理也照樣帶入。

2)typedef是在編譯時(shí)處理的。它在自己的作用域內(nèi)給一個(gè)已經(jīng)存在的類型一個(gè)別名,但是You cannot use the typedef specifier inside a functiondefinition。

3)typedef int * int_ptr;

#define int_ptr int *
作用都是用int_ptr代表 int* ,但是二者不同,正如前面所說,#define在預(yù)處理時(shí)進(jìn)行簡(jiǎn)單的替換,而typedef不是簡(jiǎn)單替換,而是采用如同定義變量的方法那樣來聲明一種類型。也就是說;

//refer to (xzgyb(老達(dá)摩))
#define int_ptr int *
int_ptr a, b; //相當(dāng)于int * a, b; 只是簡(jiǎn)單的宏替換

typedef int* int_ptr;
int_ptr a, b; //a, b 都為指向int的指針,typedef為int* 引入了一個(gè)新的助記符


這也說明了為什么下面觀點(diǎn)成立
//QunKangLi(維護(hù)成本與程序員的創(chuàng)造力的平方成正比)
typedef int * pint ;
#define PINT int *

那么:
const pint p ;//p不可更改,但p指向的內(nèi)容可更改
const PINT p ;//p可更改,但是p指向的內(nèi)容不可更改。

pint是一種指針類型 const pint p 就是把指針給鎖住了p不可更改
而const PINT p 是constint * p 鎖的是指針p所指的對(duì)象。

4)還應(yīng)經(jīng)注意到#define 不是語句不要在行末加分號(hào),否則會(huì)連分號(hào)一塊置換。


關(guān)鍵詞: 單片機(jī)C語言defin

評(píng)論


技術(shù)專區(qū)

關(guān)閉