網(wǎng)站首頁 編程語言 正文
????????宏定義是高級語言編譯器提供的常用語法,其目的是利用某一標識符標識某個文本字符串。在編寫程序時,如果程序中反復地使用某個數(shù)據(jù)或某段程序片段,就可以考慮將這個數(shù)據(jù)或程序片段定義為宏,然后每個出現(xiàn)該數(shù)據(jù)或程序片段的地方用宏名替代,選擇宏定義來做的好處是程序簡潔,可讀性好,而且當需要修改這些相同的程序片段時,只要修改宏定義中的字符串即可,不需要修改多處。
????????宏定義命令:define
? ? ? ?優(yōu)點:方便程序的修改,同時也能提高程序的運行效率。
? ? ? ? 宏定義一般有兩種形式:無參宏定義和帶參宏定義。
無參宏定義
定義形式
#define 標識符 字符串
注意:
????????1.宏定義是用宏名來表示一個字符串,在宏展開時以該字符串取代宏名,只是簡單的替換,字符串中可以含任何字符,可以是常數(shù),也可以是表達式,預處理不作任何檢查。只在編譯時檢查。
????????2.宏定義行末不必加分號(除非你的宏內(nèi)容中需要有分號)。
????????3.宏定義必須寫在函數(shù)之外,作用域為宏定義命令起到源程序結束。如要終止其作用域可使用#undef命令?
例1:輸入圓的半徑輸出圓的周長和面積
#include <stdio.h> #define PI 3.14 int main(){ int r; printf("輸入半徑:"); scanf("%d",&r); printf("圓的周長為:%.2f,面積為:%.2f",2*PI*r,PI*r*r); return 0; }
預處理階段進行宏替換↓:
#include <stdio.h> int main(){ int r; printf("輸入半徑:"); scanf("%d",&r); printf("圓的周長為:%.2f,面積為:%.2f",2*3.14*r,3.14*r*r); return 0; }
代碼輸出:?
?例2:通過宏定義輸出字符串
#include <stdio.h> #define HELLO "Hello," #define WORLD "World!" int main(){ printf(HELLO WORLD); return 0; }
預處理階段進行宏替換↓:
#include <stdio.h> int main(){ printf("Hello," "World!"); return 0; }
代碼輸出:
?
例3:請問如下代碼S1和S2的輸出是否相等
#include <stdio.h> #define S1 3+4 #define S2 (3+4) int main(){ printf("S1:%d\n",S1*5); printf("S2:%d\n",S2*5); return 0; }
預處理進行宏替換↓(這里就體現(xiàn)出了直接替換并不會因為你的宏先定義就先計算,而是替換后再做后續(xù)處理):
#include <stdio.h> #define S1 3+4 #define S2 (3+4) int main(){ printf("S1:%d\n",3+4*5); printf("S2:%d\n",(3+4)*5); return 0; }
?代碼輸出:
?帶參宏定義
定義形式
#define 宏名(形參表) 字符串
例1:M(3)==N(3)?? M(3+2)==N(3+2)?
#include<stdio.h> #define M(y) ((y)*(y)+3*(y)) #define N(y) (y*y+3*y) int main(){ printf("M(3):%d\n",M(3)); printf("N(3):%d\n",N(3)); printf("M(3+2):%d\n",M(3+2)); printf("N(3+2):%d\n",N(3+2)); }
預處理階段進行宏替換↓(這個例題主要是為了提醒大家如果要用宏定義進行一些計算,最好將參與計算的所有變量都加上括號以防本題中的情況出現(xiàn)):
#include<stdio.h> #define M(y) ((y)*(y)+3*(y)) #define N(y) (y*y+3*y) int main(){ printf("M(3):%d\n",((3)*(3)+3*(3))); printf("N(3):%d\n",(3*3+3*3)); printf("M(3+2):%d\n",((3+2)*(3+2)+3*(3+2))); printf("N(3+2):%d\n",(3+2*3+2+3*3+2)); }
?代碼輸出:
?例2:通過宏來計算數(shù)組中元素個數(shù)
#include<stdio.h> #include<stdlib.h> #include<time.h> #define Size_Array(b) sizeof(b)/sizeof(b[0]) int main(){ int i; srand((unsigned)time(NULL)); int b[i=rand()%100]; printf("隨機數(shù)為:%d 數(shù)組元素個數(shù)為:%d",i,Size_Array(b)); }
?預處理階段進行宏替換↓(很經(jīng)典的面試小題):
#include<stdio.h> #include<stdlib.h> #include<time.h> int main(){ int i; srand((unsigned)time(NULL)); int b[i=rand()%100]; printf("隨機數(shù)為:%d 數(shù)組元素個數(shù)為:%d",i,sizeof(b)/sizeof(b[0])); }
?代碼輸出:
#和##運算?
#運算 用法:
????????# 運算符的用處就是把符號轉化為字符串。例如,如果 a 是一個宏的形參,則替換文本中的 #a 則被系統(tǒng)轉化為 “a”。????????
#include <stdio.h> #define TO_STR(s) #s int main(){ printf(TO_STR(HelloWorld!)); return 0; }
?代碼輸出:?
##運算 用法:
????????## 運算符可以用在替換文本中,而它的作用是起到粘合的作用,即將兩個符號組合成一個符號。
#include <stdio.h> #define CONCAT(x,y) x##y int main(){ printf("%d", CONCAT(1,000)); return 0; }
??代碼輸出:
變參宏
用法:
? ? ? ? 當要調(diào)用printf類似不確定參數(shù)格式時可以使用__VA_ARGS__,在宏定義中,形參列表的最后一個參數(shù)為省略號“…”,“__VA_ARGS__”就可以被用在替換文本中,來表示“…”代表了什么。? ???
#define PR(...) printf(__VA_ARGS__) //宏定義 PR("hello\n"); //宏調(diào)用
例:
#include <stdio.h> #define P(X, ...) printf("get:"#X":"__VA_ARGS__) int main(){ int j=20,i=10; P(10, "j = %d\n", j); P(10, "j = %d i=%d\n", j,i); return 0; }
???代碼輸出:
?
#ifndef 條件編譯
????????#ifndef 的最主要目的是防止頭文件的重復包含和編譯。
????????c語言中,對同一個變量或者函數(shù)進行多次聲明不會報錯。所以如果.h文件里進行了聲明工作,不使用# ifndef宏定義,多個c文件包含同一個.h文件也不會報錯。
然而c++中,#ifdef的作用域只是在單個文件中。所以如果.h文件里定義了全局變量,即使采用#ifdef宏定義,多個.c文件包含同一個.h文件就會出現(xiàn)全局變量重定義的錯誤。
????????使用#ifndef可以避免這種錯誤:
#ifndef x //先測試x是否被宏定義過 #define x code1 //如果x沒有被宏定義過,定義x,并編譯code1 #endif code2 //如果x已經(jīng)定義過了則編譯code2,跳過code1
????????適當?shù)氖褂脳l件編譯和宏定義可以讓代碼的運行效率更高,特別是在進行大項目的時候當某個數(shù)值使用次數(shù)較多且修改比較頻繁的情況下,宏定義也是比較高效的(當然函數(shù)也可以,等有時間寫完函數(shù)再來比較一下函數(shù)和宏的優(yōu)缺點吧)?
原文鏈接:https://blog.csdn.net/m0_57882370/article/details/122379858
相關推薦
- 2023-02-09 Linux命令行循環(huán)執(zhí)行shell命令_linux shell
- 2022-10-09 C#實現(xiàn)折半查找算法_C#教程
- 2022-05-31 python庫pydantic的簡易入門教程_python
- 2023-01-30 python?集合常用操作匯總_python
- 2022-01-18 利用css3實現(xiàn)立體旋轉動畫效果
- 2022-07-08 C#中的圖像Image類與打印Printing類用法_C#教程
- 2022-06-24 python和Appium移動端多設備自動化測試框架實現(xiàn)_python
- 2022-05-29 C#中使用HttpPost調(diào)用WebService的方法_C#教程
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結構-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支