- 相關(guān)推薦
C語(yǔ)言#define的用法
引導(dǎo)語(yǔ):預(yù)處理器是在真正的編譯開始之前由編譯器調(diào)用的獨(dú)立程序。以下是百分網(wǎng)小編分享給大家的C語(yǔ)言#define的用法,歡迎閱讀!
#define的用法
#define 是一個(gè)預(yù)處理指令,這個(gè)預(yù)處理執(zhí)行可以定義宏。與所有預(yù)處理指令一樣,預(yù)處理指令#define用#符號(hào)作為行的開頭。預(yù)處理指令從#開始,到其后第一個(gè)換行符為止。也就是說(shuō),指令的長(zhǎng)度限于一行代碼。如果想把指令擴(kuò)展到幾個(gè)物理行,可使用反斜線后緊跟換行符的方法實(shí)現(xiàn),該出的換行符代表按下回車鍵在源代碼文件中新起一行所產(chǎn)生的字符,而不是符號(hào) \n 代表的字符。在預(yù)處理開始錢,系統(tǒng)會(huì)刪除反斜線和換行符的組合,從而達(dá)到把指令擴(kuò)展到幾個(gè)物理行的效果。可以使用標(biāo)準(zhǔn)C注釋方法在#define行中進(jìn)行注釋。
//使用反斜線+回車
#define OW "hello\
world!" /*注意第二行要左對(duì)齊*/
每一個(gè)#define行由三部分組成:
第一部分,指令#deine自身。
第二部分,所選擇的縮略語(yǔ),這些縮略語(yǔ)稱為宏(分為對(duì)象宏和函數(shù)宏)。宏的名字中不允許有空格,而且必須遵循C變量命名規(guī)則:只能使用字母、數(shù)字和下劃線(_),第一個(gè)字符不能為數(shù)字。習(xí)慣上宏名用大寫字母表示,以便于與變量區(qū)別。但也允許用小寫字母。
第三部分,(#define行的其余部分)稱為替換列表或主體。
注意,結(jié)尾沒(méi)有分號(hào)
下面來(lái)看一個(gè)例子:
#include
#define OW 2 * 2
#define OW 2 * 2
//#undef OW 需要先取消宏定義
#define OW 2*2
int main (void)
{
printf ("%d\n", OW);
return 0;
}
輸出結(jié)果:
define.c:5:0: 警告: “OW”重定義 [默認(rèn)啟用]
define.c:4:0: 附注: 這是先前定義的位置
相同定義意味著主體具有相同順序的語(yǔ)言符號(hào)。因此,下面兩個(gè)定義相同:
#define OW 2 * 2
#define OW 2 * 2
兩者都有三個(gè)相同的語(yǔ)言符號(hào),而且額外的空格不是主體的一部分。下面的定義則被認(rèn)為是不同的:
#define OW 2*2
上式只有一個(gè)(而非三個(gè))語(yǔ)言符號(hào),因此與前面兩個(gè)定義不同?梢允褂#undef指令重新定義宏。
宏所代表的數(shù)字可以在編譯命令中指定(使用-D選項(xiàng))
/*
宏演示
*/
#include
int main()
{
int num=0;
int arr[SIZE]={}; //使用gcc -D可以宏定義這個(gè)數(shù)字
for(num = 0;num <= SIZE - 1;num++)
{
arr[num]=num;
printf("%d ",arr[num]);
}
printf("\n");
return 0;
}
gcc -DSIZE=4 define.c
輸出結(jié)果:
0 1 2 3
函數(shù)宏:
通過(guò)使用參數(shù),可以創(chuàng)建外形和作用都與函數(shù)相似的類函數(shù)宏。宏的參數(shù)也用圓括號(hào)括起來(lái)。類函數(shù)宏的定義中,用圓括號(hào)括起來(lái)一個(gè)或多個(gè)參數(shù),隨后這些參數(shù)出現(xiàn)在替換部分。
#include
#define SQUARE(X) X*X
#define PR(X) printf ("The result is %d\n", X)
int main (void)
{
int x = 4;
int z;
printf ("x = %d\n", x);
z = SQUARE(x);
printf ("Evaluating SQUARE(x): ");
PR(z);
z = SQUARE(2);
printf ("Evaluating SQUARE(2): ");
PR(z);
printf ("Evaluating 100/SQUARE(2): ");
PR(100/SQUARE(2));
z = SQUARE(x+2);
printf ("Evaluating SQUARE(x+2): ");
PR(z);
printf ("x is %d\n", x);
z = SQUARE(++x);
printf ("Eavluating SQUARE(++x): ");
PR(SQUARE (++x));
printf ("After incrementing, x is %x\n", x);
return 0;
}
輸出結(jié)果:
x = 4
Evaluating SQUARE(x): The result is 16
Evaluating SQUARE(2): The result is 4
Evaluating 100/SQUARE(2): The result is 100
Evaluating SQUARE(x+2): The result is 14
x is 4
Eavluating SQUARE(++x): The result is 36
After incrementing, x is 6
SQUARE(x+2) 輸出結(jié)果是14,而不是想要的6*6 = 36。這是因?yàn)轭A(yù)處理器不進(jìn)行計(jì)算,而只進(jìn)行字符串替換。在出現(xiàn)x的地方,預(yù)處理都用字符串 x+2進(jìn)行替換。x*x 變?yōu)?x+2*x+2 根據(jù)運(yùn)算符優(yōu)先級(jí),則結(jié)果為 14
100/SQUARE(2)輸出結(jié)果是 100,而不是想要的 25。因?yàn)椋鶕?jù)優(yōu)先級(jí)規(guī)則,表達(dá)式是從左到右求值的。
100/2*2 = 100
要處理前面兩個(gè)示例中的情況,需要如下定義:
#define SQUARE(x) ((x) * (x))
從中得到的經(jīng)驗(yàn)是使用必須的足夠多的圓括號(hào)來(lái)保證以正確的順序進(jìn)行運(yùn)行和結(jié)合。
SQUARE(++x) 根據(jù)編譯器的不同會(huì)出現(xiàn)兩種不同的結(jié)果。解決這個(gè)問(wèn)題的最簡(jiǎn)單的方法是避免在宏的參數(shù)中使用++x。一般來(lái)說(shuō),在宏中不要使用增量或減量運(yùn)算符。
參看:C 語(yǔ)言再學(xué)習(xí) -- 運(yùn)算符與表達(dá)式
利用宏參數(shù)創(chuàng)建字符串:#運(yùn)算符
在類函數(shù)宏的替換部分中,#符號(hào)用作一個(gè)預(yù)處理運(yùn)算符,它可以把語(yǔ)言符號(hào)轉(zhuǎn)化為字符串。
例如:如果x是一個(gè)宏參量,那么#x可以把參數(shù)名轉(zhuǎn)化為相應(yīng)的字符串。該過(guò)程稱為字符串化。
#include
#define PSQR(x) printf ("The square of " #x" is %d\n", ((x)*(x)))
int main (void)
{
int y = 2;
PSQR (y);
PSQR (2 + 4);
return 0;
}
輸出結(jié)果:
The square of y is 4
The square of 2 + 4 is 36
#include
#include
#define VEG(n) #n
int main()
{
char str[20];
strcpy(str,VEG(num));//num
printf("%s\n",str);//拷貝
return 0;
}
輸出結(jié)果:
num
預(yù)處理器的粘合劑:##運(yùn)算符
和#運(yùn)算符一樣,##運(yùn)算符可以用于類函數(shù)宏的替換部分。另外,##還可用于類對(duì)象宏的替換部分。這個(gè)運(yùn)算符把兩個(gè)語(yǔ)言符號(hào)組合成單個(gè)語(yǔ)言符號(hào)。
#include
#define XNAME(n) x##n
#define PRINT_XN(n) printf ("x"#n" = %d\n", x##n)
int main (void)
{
int XNAME (1) = 14; //變?yōu)?int x1 = 14;
int XNAME (2) = 20; //變?yōu)?int x2 = 20;
PRINT_XN (1); //變?yōu)?printf ("x1 = %d\n", x1);
PRINT_XN (2); //變?yōu)?printf ("x2 = %d\n", x2);
return 0;
}
輸出結(jié)果:
x1 = 14
x2 = 20
宏用于簡(jiǎn)單函數(shù):
#include
#define MAX(x,y) ((x)>(y) ? (x) : (y)) /*比較大小*/
#define ABS(x) ((x) < 0 ? -(x) : (x)) /*絕對(duì)值*/
#define ISSIGN(x) ((x) == '+' || (x) == '-' ? 1 : 0) /*正負(fù)號(hào)*/
int main()
{
printf ("較大的為: %d\n", MAX(5,3));
printf ("絕對(duì)值為: %d\n", ABS (-2));
printf ("正負(fù)號(hào)為: %d\n", ISSIGN ('+'));
return 0;
}
輸出結(jié)果:
較大的為: 5
絕對(duì)值為: 2
正負(fù)號(hào)為: 1
下面是需要注意的幾點(diǎn):
1、宏的名字中不能有空格,但是在替代字符串中可以使用空格。ANSI C 允許在參數(shù)列表中使用空格。
2、用圓括號(hào)括住每個(gè)參數(shù),并括住宏的整體定義。
3、用大寫字母表示宏函數(shù)名,便于與變量區(qū)分。
4、有些編譯器限制宏只能定義一行。即使你的編譯器沒(méi)有這個(gè)限制,也應(yīng)遵守這個(gè)限制。
5、宏的一個(gè)優(yōu)點(diǎn)是它不檢查其中的變量類型,這是因?yàn)楹晏幚碜址妥址,而不是?shí)際值。
面試:用預(yù)處理指令#define 聲明一個(gè)常數(shù),用以表明1年中有多少秒(忽略閏年問(wèn)題)
#define SEC (60*60*24*365)UL
考察內(nèi)容:
1、懂得預(yù)處理器將為你計(jì)算常量表達(dá)式的值,因此,可直接寫出你是如何計(jì)算一年中有多少秒而不是計(jì)算出實(shí)際的值,這樣更清晰而沒(méi)有代價(jià)。
2、意識(shí)到這個(gè)表達(dá)式將使一個(gè)16 位機(jī)的整形數(shù)溢出,因此要用到長(zhǎng)整形符號(hào) L ,告訴編譯器這個(gè)常數(shù)是長(zhǎng)整形數(shù)。
3、如果你在你的表達(dá)式中用到UL(表示無(wú)符號(hào)長(zhǎng)整型),那么你有了一個(gè)好的起點(diǎn)。
面試:寫一個(gè)“標(biāo)準(zhǔn)”宏MIN ,這個(gè)宏輸入兩個(gè)參數(shù)并返回較小的一個(gè)
#define MIN(A,B) ((A) <= (B) ? (A) : (B))
考察內(nèi)容:
1、三目表達(dá)式的使用
2、使用必須的足夠多的圓括號(hào)來(lái)保證以正確的順序進(jìn)行運(yùn)行和結(jié)合
3、進(jìn)一步討論,在宏中不要使用增量或減量運(yùn)算符
參看:宏名必須用大寫字母嗎?
研究:C語(yǔ)言中用宏定義(define)表示數(shù)據(jù)類型和用typedef定義數(shù)據(jù)類型有什么區(qū)別?
宏定義只是簡(jiǎn)單的字符串代換,是在預(yù)處理完成的,而typedef是在編譯時(shí)處理的,它不是作簡(jiǎn)單的代換,而是對(duì)類型說(shuō)明符重新命名。被命名的標(biāo)識(shí)符具有類型定義說(shuō)明的功能。
請(qǐng)看下面的例子:
#define P1 int *
typedef (int *) P2
從形式上看這兩者相似,但在實(shí)際使用中卻不相同。
下面用P1、P2說(shuō)明變量時(shí)就可以看出它們的區(qū)別:
P1 a, b; 在宏代換后變成: int *a, b; 表示 a 是指向整型的指針變量,而 b 是整型變量。
P2 a, b; 表示a,b都是指向整型的指針變量。因?yàn)镻IN2是一個(gè)類型說(shuō)明符。
由這個(gè)例子可見(jiàn),宏定義雖然也可表示數(shù)據(jù)類型, 但畢竟是作字符代換。在使用時(shí)要分外小心,以避出錯(cuò)。
總結(jié),typedef和#define的不同之處:
1、與#define不同,typedef 給出的符號(hào)名稱僅限于對(duì)類型,而不是對(duì)值。
2、typedef 的解釋由編譯器,而不是是處理器執(zhí)行。
3、雖然它的范圍有限,但在其受限范圍內(nèi),typedef 比 #define 更靈活。
用于定義字符串,尤其是路徑
A),#define ENG_PATH_1 E:\English\listen_to_this\listen_to_this_3
B),#define ENG_PATH_2 “ E:\English\listen_to_this\listen_to_this_3”
A 為 定義路徑, B 為定義字符串
C), #define ENG_PATH_3 E:\English\listen_to_this\listen\
_to_this_3
還沒(méi)發(fā)現(xiàn)問(wèn)題?這里用了 4 個(gè)反斜杠,到底哪個(gè)是接續(xù)符?回去看看接續(xù)符反斜杠。反斜杠作為接續(xù)符時(shí),
在本行其后面不能再有任何字符,空格都不行。所以,只有最后一那給 ENG_PATH_1 加上雙引號(hào)不就成了:“ENG_PATH_1”。但是請(qǐng)注意:有的系統(tǒng)里規(guī)定路徑的要用雙反斜杠“ \\” ,比如:
#define ENG_PATH_4 E:\\English\\listen_to_this\\listen_to_this_3
【C語(yǔ)言#define的用法】相關(guān)文章:
C語(yǔ)言for語(yǔ)句用法詳解11-19
c語(yǔ)言問(wèn)號(hào)冒號(hào)的用法01-08
c語(yǔ)言大括號(hào)的用法11-28
C語(yǔ)言預(yù)定義宏用法03-30
C語(yǔ)言中strpbr()函數(shù)的用法03-19
C語(yǔ)言assert的用法有哪些04-02