日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【C语言进阶】预定义详解

發(fā)布時間:2023/12/20 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【C语言进阶】预定义详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

預(yù)定義

  • 一、預(yù)定義符號
  • 二、#define
    • 1.#define定義標識符
    • 2.#define定義宏
    • 3.#define替換規(guī)則
    • 4.#和##
      • 4.1 #號
      • 4.2 ##號
  • 三、函數(shù)與宏
    • 1.代碼長度
    • 2.執(zhí)行速度
    • 3.操作符的優(yōu)先級
    • 4.參數(shù)類型
    • 5.調(diào)試
    • 6.遞歸
    • 7.帶有副作用的參數(shù)
  • 四、條件編譯

一、預(yù)定義符號

預(yù)定義符號是C標準定義的宏定義符號
例如 FILE LINE DATE TIME STDC(如果編譯器遵循ASCI C就返回1,否則未定義。)

int main() {printf("%s\n",__FILE__);printf("%d\n",__LINE__);printf("%s\n",__DATE__);printf("%s\n",__TIME__);//printf("%s\n__STDC__); }

二、#define

1.#define定義標識符

語法:
define name stuff

(而這個stuff可以是不同的類型)

1.#define MAX 100
2.#define reg register(給register起一個短一點的名字)
3.#define arr “hello world.”
我們也可以利用這個來寫一個死循環(huán)

#define do_forever for(; ;)

當然在寫代碼的時候會有這樣一個疑問,如果要寫的stuff過長怎么辦?這個時候我們可以分行寫,但是除了最后一行外,每一行都要加一個反斜杠(續(xù)航符)

#define fad printf("name:%s\tage:%s\t \tele:%s\taddre:%s\t",\name,age\tele,addre)

2.#define定義宏

#define機制包括了一個規(guī)定,允許把參數(shù)替換到文本中,這種實現(xiàn)通常稱為宏 (macro)或者定義宏(define macro)。

宏的申明方式
#define name(parament-list) stuff
其中parament-list是一個由逗號隔開的符號表,有可能會出現(xiàn)在后面的stuff中。
注意:參數(shù)列表的左括號必須與name緊鄰,不能有空格或者空白,否則會被認為是stuff的一部分。

在定義宏時要合理使用括號,防止運算符的優(yōu)先級問題

#define SQUARE(x) x*xint main() {int a = 4;printf("%d", SQUARE(a));return 0; }


但如果換成SQUARE(4+1)呢

#define SQUARE(x) x*xint main() {//int a = 4;printf("%d", SQUARE(4+1));return 0; }


我們可以看到結(jié)果是9,那是因為替換方式

#define SQUARE(x) 4+1*4+1

這樣就提醒我們在寫的時候最好帶上括號

#define SQUARE(x) (x)*(x)int main() {//int a = 4;printf("%d", SQUARE(4+1));return 0; }


但是這樣寫任然不夠嚴密,在有些時候還是會出現(xiàn)錯誤

將上述代碼中printf一部分換成
printf(“%f”, 1.0/SQUARE(4+1))


答案顯然不對,按上述的替換法方式就變成了
#define SQUARE(x) 1.0/(4+1)*(4+1)
那么這樣得出錯誤的結(jié)果也就不奇怪了
為了達到最初的目的,我們應(yīng)該這樣

#define SQUARE(x) ((x)*(x))int main() {//int a = 4;printf("%f", 1.0/SQUARE(4+1));return 0; }

當然還有一個特殊的地方就是不要在定義標識符或者定義宏時加上分號(;),這樣很容易在使用時出錯

#define SQUARE(x) ((x)*(x));int main() {if(1)int a=SQUARE(4);printf("%d", a);return 0; }

編譯預(yù)處理完,替換之后就變成了

if(1) >int a=((4)*(4));;

if后面沒有大括號跟兩條語句是不對的

所以我們在定義標識符或者定義宏時不要加上分號,避免上述錯誤。

3.#define替換規(guī)則

在程序中擴展#define定義符號和宏時,需要涉及幾個步驟。

1.在調(diào)用宏時,首先多參數(shù)進行檢查,看看是否包括任何由#define定義的符號,如果是他們首先被替換。
2.替換文本隨后被插入到程序中原來文本的位置。對于宏,參數(shù)名被他們的只所替換。
3.最后,再次對結(jié)果文件進行掃描,看看它是否包含任何由#define定義的符號。如果是,就重復(fù)上述處理過程。
在這里有幾個需要注意的地方
1.宏參數(shù)和#define定義中可以出現(xiàn)其他#define定義的符號,但是對于宏,不能出現(xiàn)遞歸。
2.當預(yù)處理器搜索#define定義的符號的時候,字符串常量的內(nèi)容并不被搜索。

4.#和##

4.1 #號

如何把參數(shù)插入到字符串中?
首先我們要知道字符串是有自動連接的功能的的特點的。
比如:

int main() {printf("hello""world");return 0; }


而#號加在宏參數(shù)前時,可以將這個參數(shù)轉(zhuǎn)化為字符串。

int main() {int a = 10;printf("the value of a is %d\n", a);int b = 20;printf("the value of b is %d\n", b);float c = 30.0f;printf("the value of c is %f\n", c);return 0; }

可以看出只有a,b,c和%d,%f不同,這個時候可以用宏來寫

#define PRINT(x,format) printf("the value of "#x" is "format"\n",x) int main() {int a = 10;PRINT(a, "%d");int b = 20;PRINT(b, "%d");float c = 30.0f;PRINT(c, "%f");return 0; }

4.2 ##號

##的作用是將兩個字符合成一個字符。

#define A(x,y) printf("%d\n",x##y) int main() {int ab = 20;A(a, b);return 0; }

三、函數(shù)與宏

1.代碼長度

宏:每次使用時在編譯的預(yù)處理階段宏的代碼就會插入到程序中,如果宏的代碼量很大的話,那么整體的代碼量也會大大增加。
函數(shù):函數(shù)的代碼只有一份,每次調(diào)用都從這里調(diào)用。

2.執(zhí)行速度

宏比函數(shù)在速度和規(guī)模上都要更勝一籌。

3.操作符的優(yōu)先級

宏可能會帶來操作符的優(yōu)先級的問題。
比如上面已經(jīng)提過的:

#define SQUARE(x) x*xint main() {//int a = 4;printf("%d", SQUARE(4+1));return 0; }

執(zhí)行答案是9,但是我們的目的是算(4+1)*(4+1)

4.參數(shù)類型

宏:參數(shù)與類型無關(guān),只要參數(shù)合法就可以使用
函數(shù):只能在類型合適的表達式上使用,即參數(shù)必須聲明為特定的類型。

當然,因為函數(shù)與參數(shù)無關(guān)也就不夠嚴謹。
比如,對于比較大小,宏可以比較不同類型的大小(整形,浮點型等等)

#define MAX(x,y) ((x)>(y)?(x):(y))

5.調(diào)試

宏:由于宏是在編譯預(yù)處理直接替換的,所以無法調(diào)試
函數(shù):可以調(diào)試在vs2019下,按F10是逐過程,F11是逐語句(可以進入函數(shù)內(nèi)部調(diào)試)。

6.遞歸

宏是不能遞歸的
函數(shù)可以,比如用遞歸寫斐波那契數(shù)列

int fib(int n) {if (n == 0 || n == 1)return n;elsereturn fib(n - 1) + fib(n - 2); }

7.帶有副作用的參數(shù)

宏:宏參數(shù)可能被替換到多個位置,更容易出現(xiàn)問題
函數(shù):只在傳參時計算一次,結(jié)果不容易出錯
比如:

#define MAX(x,y) printf("%d",((x)>(y)?(x):(y))) int main() {int a = 1;int b = 2;MAX(++a, ++b);return 0;

我們這里想要比較a++和b++ 的大小,也就是2和3的大小
我們想要的答案應(yīng)該是3才對
但事實上

這是因為經(jīng)過替換后
#define MAX(x,y) printf(“%d”,((++a)>(++b)?(++a):(++b)))
所以答案為4

這也是提醒我們在使用宏時不要使用帶有副作用的參數(shù)

四、條件編譯

在編譯一個程序的時候,可以用條件編譯來選擇將一條語句編譯或者放棄。

#include <stdio.h> #define __DEBUG__ int main() {int i = 0;int arr[10] = { 0 };for (i = 0; i < 10; i++){arr[i] = i; #ifdef __DEBUG__//判斷是否已經(jīng)定義,如果定義了就執(zhí)行下面的語句printf("%d\n", arr[i]); #endif }return 0; }

1. #if 常量表達式 //... #endif //常量表達式由預(yù)處理器求值。 如: #define __DEBUG__ 1 #if __DEBUG__ //.. #endif 2.多個分支的條件編譯 #if 常量表達式 //... #elif 常量表達式 //... #else //... #endif 3.判斷是否被定義 #if defined(symbol) //等于 #ifdef symbol #if !defined(symbol)// #ifndef symbol4.嵌套指令(與if嵌套相似) #if defined(OS_UNIX) #ifdef OPTION1 unix_version_option1(); #endif #ifdef OPTION2 unix_version_option2(); #endif #elif defined(OS_MSDOS) #ifdef OPTION2 msdos_version_option2(); #endif #endif

總結(jié)

以上是生活随笔為你收集整理的【C语言进阶】预定义详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。