C語言之宏詳解(超級詳細!)

目錄

一、用宏前須知-#define相關知識

????????大致結構:

?????????對預定義符號的補充:

二、用#define定義宏

????????什么是宏?

????????#define的替換規則:

三、常用的宏定義

1、宏定義常量

2、定義一個宏語句

3、宏定義函數

????????宏與函數的對比:

4、#和## 分別字符串化和將兩個符號連接成一個符號?

#字符串化

?##將兩個符號連接成一個符號

四、與宏相關的作用符號

1、換行符 '\'

2、取消宏定義#undef?

五、命名約定


一、用宏前須知-#define相關知識

????????大致結構:

#define ???name ???stuff自定義名 ???內容

????????栗子:

#define OP 256
#define YU "youarewelcome"
#define S(r) (r*r)
#define REG register ? ? ? ? ?//為 register這個關鍵字,創建一個簡短的名字
#define PRINT printf("file:%s line:%d\n", __FILE__, __LINE__)//__FILE__,__LINE__這是個啥?別急后面有補充!#include<stdio.h>
int main()
{printf("%d \n", OP);printf("%s \n",YU);printf("%d \n", S(6));PRINT;return 0;
}

? ? ? ? ?


?????????對預定義符號的補充:

__FILE__      //進行編譯的源文件 
__LINE__     //文件當前的行號 
__DATE__    //文件被編譯的日期 
__TIME__    //文件被編譯的時間 
__STDC__    //如果編譯器遵循ANSI C,其值為1,否則未定義

二、用#define定義宏

????????什么是宏?

????????宏可以看作為一些命令的集合。它是一種預處理器指令,在預編譯階段將宏名替換為后面的替換體。

????????而#define可以用來定義宏:

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

????????宏的聲明方式:

??#define name( parament-list ) stuff
//其中的 parament-list 是一個由逗號隔開的符號表,它們可能出現在stuff中

? ? ? ? 栗子:

????????實現一個開平方的宏? ? ? ??

#define SQ(x) x*xprintf("%d \n", SQ(7));

????????他的實際執行結構為7*7->即為49

????????還是用這個我們剛剛定義的宏

????????我們執行下面這段代碼:???????

int a=6;printf("%d \n", SQ(6+1));

????????他的實際執行結構為6+1*6+1->即為13

????????這說明了什么?這印證了上面所說的宏是把參數替換到文本中,也就是宏直接吧6+1替換掉了x直接帶入了后面的表達式當中了!

????????對此,根據我們原來的用意。這時我們可以用括號來解決這個問題:

#define SQ(x) (x)*(x)

????????這給了我們一個提醒:我們在用宏時最好多用括號,以此來避免不必要的錯誤!

再看個栗子:

#define DOUBLE(x) (x) + (x) 
int a = 5; 
printf("%d\n" ,10 * DOUBLE(a));

????????在這個例子中我們對這個宏使用了括號,乍一看這個例子輸出的值像是100

????????但是實際呢?上圖!

? ? ??

來看看實際它怎么執行的,它執行替換操作實際上為:

printf?("%d\n",10 *?(5) +?(5));

????????因此我們說定義宏要多用括號!

#define DOUBLE( x) ??( ( x ) + ( x ) )

????????改成這樣就能實現想要的效果啦!


????????#define的替換規則:

????????在程序中擴展#define 定義符號和宏時,需要涉及幾個步驟:
1. 在調用宏時,首先對參數進行檢查,看看是否包含任何由 #define 定義的符號。如果是,它們首先被替換。
2. 替換文本隨后被插入到程序中原來文本的位置。對于宏,參數名被他們的值所替換。
3. 最后,再次對結果文件進行掃描,看看它是否包含任何由 #define 定義的符號。如果是,就重復上 述處理過程。
????????注意:
1. 宏參數和 #define 定義中可以出現其他 #define 定義的符號。但是對于宏,不能出現遞歸。
2. 當預處理器搜索 #define 定義的符號的時候,字符串常量的內容并不被搜索。

三、常用的宏定義

1、宏定義常量

?????????定義諸如:字符串、整形數、浮點型數等等的常量.

????????栗子:

#define AO 114514
#define NTR "我可太喜歡了"
#define KK 3.14
#include<stdio.h>
int main()
{printf("%d %s %f", AO, NTR, KK);return 0;
}

? ? ? ?


2、定義一個宏語句

????????栗子:

#include<stdio.h>
#define PFINT printf("hello world!\n");
int main()
{PFINT///預處理時會被替換為 printf("hello world!\n");return 0;
}

3、宏定義函數

????????宏可以接受參數,類似于真正的函數一樣。具體的接受參數方法與函數差不多,只不過不用指定函數類型,這也是宏定義函數的一個優勢!比如:當我定義了一個函數有時要傳整形,有時要傳浮點型,函數可能要根據類型來多定義幾個,而宏只需要一個就行了!

????????栗子1:

#define MAX(a, b) ((a)>(b)?(a):(b))
#include<stdio.h>int main()
{printf("%d", MAX(114, 514));return 0;
}

? ? ? ?

????????栗子2:

#define MALLOC(num, type)\ 
(type *)malloc(num * sizeof(type)) //這和\是干啥的?詳見地四大點\的作用
... 
//使用 
MALLOC(10, int);//類型作為參數 
//預處理器替換之后: 
(int *)malloc(10 * sizeof(int)); 

????????這個例子中,函數是做不到跟宏相同的效果的,所以說為啥有了函數我們還要定義宏呢?這個就是一個很明顯的例子。


????????宏與函數的對比:


4、#和## 分別字符串化將兩個符號連接成一個符號?

#字符串化

????????這個很好理解看看例子就會了!

????????栗子:

#define STR(exp) printf("%s\n",#exp);
#include<stdio.h>
int main()
{STR(for fun)return 0;
}

? ? ??


?##將兩個符號連接成一個符號

????????##可以把位于它兩邊的符號合成一個符號。 它允許宏定義從分離的文本片段創建標識符。

????????栗子:

#include<stdio.h>
#define ADD_TO(num, value) num##valueint main()
{int a = ADD_TO(114, 514);printf("%d \n", a);return 0;
}

? ? ? ?


四、與宏相關的作用符號

1、換行符 '\'

????????在每行末尾(除了最后一行)加上"\",代表換行的意思。這個目的是為了不讓代碼冗余,如果代碼都擠在一段,代碼就不美觀,可讀性不好。

????????栗子:

#include<stdio.h>
#define PFINT printf("hello world!\n");\printf("goodbye world!\n");
#define NUM 1,\2,\3
int main()
{PFINTint x[] = { NUM };//->int x[] = { 1,2,3 };printf("%d %d %d \n", x[0], x[1], x[2]);return 0;
}

? ? ? ?


2、取消宏定義#undef?

????????這條指令用于移除一個宏定義。????????

#define SORT 1000
#undef SORT

????????在#undef之后SORT就相當于沒有定義,失效了。再使用則會報錯!


五、命名約定

? ? ? ? 細心的朋友可能發現了!我在定義宏時用的都是大寫的字母來作為它自定義的名字!

????????這是因為這有一個默認的命名約定:

????????一般來講函數的宏的使用語法很相似。所以語言本身沒法幫我們區分二者。

????????那我們平時的一個習慣是:

????????把宏名全部大寫

????????函數名不要全部大寫? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?


???????感謝你耐心的看到這里?( ′・?・` )比心,如有哪里有錯誤請踢一腳作者o(╥﹏╥)o!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/18186.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/18186.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/18186.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

29【PS 作圖】宮燈 夜景轉換

夜景轉化 1 原圖 2 選中要變換的圖層,然后點擊“顏色查找” 再3DLUT文件中,選擇moonlight.3DL,可以快速把圖層變成偏夜景的顏色 結果如下: 3 選擇“曲線” 把曲線 右邊往上調【亮的更亮】,左邊往下調【暗的更暗】 4 添加燈光 新建一個圖層

前端面試題大合集8----性能優化篇

一、哪些方法可以提升網站前端性能 1、Http請求優化 主要分為減少Http請求次數&#xff0c;減小請求數據量和緩存三方面。 減少Http請求次數&#xff0c;可以通過以下方法實現&#xff1a; 合并js、css文件&#xff1b;使用css-spirites技術合并圖片&#xff1b;壓縮圖片大…

HTML+CSS+JS簡易計算器

HTMLCSSJS簡易計算器 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>簡易計算器</t…

AAA實驗配置

一、實驗目的 掌握AAA本地認證的配置方法 掌握AAA本地授權的配置方法 掌握AAA維護的方法 1.搭建實驗拓撲圖 2.完成基礎配置&#xff1a; 3.使用ping命令測試兩臺設備的連通性&#xff1a; 二、配置AAA 1.打開R1&#xff1a;配置AAA方案 這兩個方框內的可以改名&#xff0c…

百度頁面奔跑的白熊html、css

一、相關知識-動畫 1.基本使用&#xff1a;先定義再調用 2. 調用動畫 用keyframes定義動畫&#xff08;類似定義類選擇器&#xff09; keyframes動畫名稱{ 0%{ width:100px&#xff1b; } 100%{ width:200px; } } 使用動畫 div { width:200px; height:200px; background-…

前端面試題日常練-day28 【面試題】

題目 希望這些選擇題能夠幫助您進行前端面試的準備&#xff0c;答案在文末。 1. 在Vue中&#xff0c;以下哪個選項用于監聽組件生命周期鉤子函數&#xff1f; a) watch b) computed c) lifecycle d) created 2. 在Vue中&#xff0c;以下哪個選項用于在列表渲染時為每個元素…

Pytorch線性模型(Linear Model)

基本步驟 ①首先準備好數據集&#xff08;DataSet&#xff09; ②模型的選擇或者設計&#xff08;Model&#xff09; ③進行訓練&#xff08;Train&#xff09;大部分模型都需要訓練&#xff0c;有些不需要。這一步后我們會確定不同特征的權重 ④推理&#xff08;inferring…

開封旅游三天兩夜旅游攻略

開封是一座歷史悠久的城市&#xff0c;有著豐富的文化遺產和美食。以下是一個三天兩夜的開封旅游攻略&#xff0c;供你參考&#xff1a; 一、行程安排 第一天&#xff1a; 上午&#xff1a;抵達開封&#xff0c;前往酒店辦理入住手續。隨后參觀開封博物館&#xff0c;了解開封…

【Python安全攻防】【網絡安全】一、常見被動信息搜集手段

一、IP查詢 原理&#xff1a;通過目標URL查詢目標的IP地址。 所需庫&#xff1a;socket Python代碼示例&#xff1a; import socketip socket.gethostbyname(www.163.com) print(ip)上述代碼中&#xff0c;使用gethostbyname函數。該函數位于Python內置的socket庫中&#xf…

廣場舞團|基于SprinBoot+vue的廣場舞團系統(源碼+數據庫+文檔)

廣場舞團系統 目錄 基于SprinBootvue的廣場舞團系統 一、前言 二、系統設計 三、系統功能設計 1 系統功能模塊 2 后臺登錄模塊 5.2.1管理員功能模塊 5.2.2社團功能模塊 5.2.3用戶功能模塊 四、數據庫設計 五、核心代碼 六、論文參考 七、最新計算機畢設選題推…

Pytorch-06 使用GPU加速計算

要在PyTorch中使用GPU加速計算&#xff0c;需要將模型和數據移動到GPU上進行處理。以下是上一節演示修改后的示例代碼&#xff0c;展示了如何在訓練過程中利用GPU加速計算&#xff1a; import torch import torch.nn as nn import torch.optim as optim import time# 檢查GPU是…

2024-05-28 問AI: 在深度學習中,什么是反向隨機失活?

文心一言 在深度學習中&#xff0c;反向隨機失活&#xff08;Inverse Randomized Elimination&#xff0c;通常稱為Dropout&#xff09;是一種在訓練深度神經網絡時常用的正則化技術&#xff0c;用于防止過擬合。該技術通過隨機將神經網絡中的一部分神經元“失活”或“丟棄”來…

深度剖析:為什么 Spring 和 IDEA 都不推薦使用 @Autowired 注解

目錄 依賴注入簡介 Autowired 注解的優缺點 Spring 和 IDEA 不推薦使用 Autowired 的原因 構造器注入的優勢 Autowired 注解的局限性 可讀性和可測試性的問題 推薦的替代方案 構造器注入 Setter 注入 Java Config Bean 注解 項目示例&#xff1a;Autowired vs 構造器…

Android 項目Gradle文件講解(Groovy和Kotlin)

Android 項目Gradle文件講解&#xff08;Groovy和Kotlin&#xff09; 前言正文一、Gradle的作用二、Gradle的種類① 工程build.gradle② 項目build.gradle③ settings.gradle④ gradle.properties⑤ gradle-wrapper.properties⑥ local.properties 三、Groovy和Kotlin的語言對比…

裝飾模式:雞腿堡

文章目錄 UML類圖目錄結構Humburger.javaChickenBurger.javaCondiment.javaChuilli.javaLettuce.javaTest.java深度理解test怎么寫 UML類圖 目錄結構 我們從指向最多的開始寫 Humburger.java package zsms;public abstract class Humburger {protected String name;public S…

【接口自動化_05課_Pytest接口自動化簡單封裝與Logging應用】

一、關鍵字驅動--設計框架的常用的思路 封裝的作用&#xff1a;在編程中&#xff0c;封裝一個方法&#xff08;函數&#xff09;主要有以下幾個作用&#xff1a;1. **代碼重用**&#xff1a;通過封裝重復使用的代碼到一個方法中&#xff0c;你可以在多個地方調用這個方法而不是…

C++貪心算法(3)

整數區間 #include<bits/stdc.h> using namespace std; int main() {int n;cin>>n;int a[110][10]{0};for(int i0;i<n;i){cin>>a[i][1]>>a[i][2];}int cnt[110]{0};int mi99999;int mii-1;bool f[110]{false,false,false,false,false,false,false,…

debian讓dotnet 程序以守護進程方式運行,如果意外退出主動開啟

創建服務文件: 打開一個新的.service文件在/etc/systemd/system/目錄下&#xff0c;例如myapp.service sudo nano /etc/systemd/system/myapp.service編輯服務文件: 添加以下內容到myapp.service文件&#xff0c;確保修改ExecStart以指向你的.NET Core應用程序的可執行文件&am…

JVM-調優之-高內存占用問題排查

排查思路 1&#xff09;檢查jvm內存的分配情況 2&#xff09;檢查jvm的gc情況 3&#xff09; 找出占用量比較大的對象 第一步&#xff1a;jmap -heap PID 查看jvm內存使用情況 jmap -heap 2525 可以看到老年代年輕代等其他內存區域內存使用率百分比 第二步&#xff1a;jsta…

Golang:使用roylee0704/gron實現定時任務

可以使用roylee0704/gron實現定時任務 文檔 https://github.com/roylee0704/gronhttps://pkg.go.dev/github.com/roylee0704/gron 安裝 go get github.com/roylee0704/gron代碼示例 package mainimport ("fmt""time""github.com/roylee0704/gron…