浅谈C++/C关于#define的那些奇奇怪怪的用法 前言众所周知#define(也就是宏定义)在C/C里用处很广泛。对于一个萌新小白来说宏定义有以下几种用法1 缩减代码第一种用法与typedef类似而且比typedef应用得更广泛。举个例子在以下C程序中unsigned int出现的实在是太多了。12345678910111213141516171819#includebits/stdc.husingnamespacestd;unsignedintn;intmain(){cinn;for(unsignedinti0;in;i){unsignedinta,b;cinab;while(b0){unsignedintra%b;ab;br;}coutaendl;}return0;}那该怎么办呢其实只需要加一行这样的代码然后再把unsigned int改成ui就可以了。1#define ui unsigned int这样的话程序就简短了很多。123456789101112131415161718192021#includebits/stdc.h#define ui unsigned int//也可以写作typedef unsigned int uiusingnamespacestd;ui n;intmain(){cinn;for(ui i0;in;i){ui a,b;cinab;while(b0){ui ra%b;ab;br;}coutaendl;}return0;}2 定义变量第二种用法与const auto(不一定是int)相似。当我们想写一段这样的代码时我们可以用const int写以避免重复出现10000512345678910111213#includebits/stdc.husingnamespacestd;constintN100005;inta[N],b[N],c[N],ans[N];intmain(){intn;cinn;for(inti0;in;i) cina[i]b[i]c[i];for(inti0;in;i) ans[i]a[i]b[i]-c[i];for(inti0;in;i) coutans[i] ;return0;}#define也有这个功能。它可以根据赋的“值”(不一定是值)判断改用哪种数据类型(这里就不细讲了)与auto的功能相似。因此我们也可以这样写12345678910111213#includebits/stdc.h#define N 100005//会根据后面的量以决定数据类型usingnamespacestd;inta[N],b[N],c[N],ans[N];intmain(){intn;cinn;for(inti0;in;i) cina[i]b[i]c[i];for(inti0;in;i) ans[i]a[i]b[i]-c[i];for(inti0;in;i) coutans[i] ;return0;}以下是#define的基础用法。其实#define还有一些其他功能。3 代替函数以以下程序为例在输出环节多次出现了同一行代码。那该怎么办呢123456789101112131415161718192021#includebits/stdc.husingnamespacestd;multisetints;intn,m;multisetint::iterator it,ie;intmain(){cinn;for(inti1;in;i){cinm;s.insert(m);}for(its.begin();it!s.end();it){if(it!s.begin()){if(*it!*ie) cout*it s.count(*it)endl;}elsecout*it s.count(*it)endl;ieit;}return0;}我们可以写一个输出函数。这样的话程序就变成了这个样子1234567891011121314151617181920212223#includebits/stdc.husingnamespacestd;multisetints;intn,m;multisetint::iterator it,ie;voidsc(multisetint::iterator a){cout*a s.count(*a)endl;}intmain(){cinn;for(inti1;in;i){cinm;s.insert(m);}for(its.begin();it!s.end();it){if(it!s.begin()){if(*it!*ie) sc(it);}elsesc(it);ieit;}return0;}同时我们也可以用#define对程序进行再一次优化(这是typedef做不到的)。这样的话程序代码就会大大缩减。123456789101112131415161718192021222324#includebits/stdc.h#define tor multisetint::iterator#define mi multisetintusingnamespacestd;mi s;intn,m;tor it,ie;voidsc(tor a){cout*a s.count(*a)endl;}intmain(){cinn;for(inti1;in;i){cinm;s.insert(m);}for(its.begin();it!s.end();it){if(it!s.begin()){if(*it!*ie) sc(it);}elsesc(it);ieit;}return0;}但其实输出函数那一部分也可以用#define做。可以用#define这样写输出函数1#define sc(a) cout*a s.count(*a)endl;//不需要tor,否则会报错可以发现这里的功能是不需要tor的。所以可以发现这个功能是第二个功能的衍生功能。总结一下就是#define可以代替一些简单函数。4 函数做不到的功能同时#define也可以做到一些函数做不到的功能。比如说前面这段程序还可以继续简化成这样1234567891011121314#includebits/stdc.h#define N 100005#define go(n) for(int i0;in;i)usingnamespacestd;inta[N],b[N],c[N],ans[N];intmain(){intn;cinn;go(n) cina[i]b[i]c[i];go(n) ans[i]a[i]b[i]-c[i];go(n) coutans[i] ;return0;}那这是为什么呢因为#define还可以用来代替重复出现多次的代码。运用这个方法我们可以用C语言写以下程序12345678910111213141516#includestdio.h#define N 100005#define go(n) for(int i0;in;i)inta[N],n,b[N];intmain(){scanf(%d,n);go(n)scanf(%d,a[i]);go(n){if(i0) b[i]a[i]a[n-1];elseb[i]a[i]a[i-1];printf(%d ,b[i]);}return0;}而且这个程序还能通过编译所以#define是可以套循环的。同时我们还可以用#define写一个forever(Scratch上死循环的英文)1#define forever() for(int i0;;i)或者这样写forever1#define forever(i) for(i0;;i)这样写死循环时就便利多了(话说while(10)它不香吗)。5 一些有些邪门的用法那#define既然那么好用那有没有一些邪门点的用法当然有。比如说以下这一段C语言程序就把邪门二字刻在了脑门上123456789101112#includestdio.h#define forever(i,j) for(int i0;;i)intI,love,you;voiddear(intd,ints,intx){forever(s,x) dear(d,s,x);}intmain(){scanf(%d%d%d,I,love,you);forever(love,you) dear(I,love,you);}不说递归加循环把程序卡死这变量用的也太阴间了吧这还是C语言程序(看来这才是forever的真正用法。)好了回到正题。那能不能用#define对#include进行缩减这里以下方的C程序为例。123456789101112131415161718#includebits/stdc.h#includewindows.husingnamespacestd;voidHideScreen(){HWNDhwnd;hwndFindWindow(ConsoleWindowClass,NULL);if(hwnd) ShowWindow(hwnd,SW_HIDE);return;}//千万别试intmain(){HideScreen();intxGetSystemMetrics(SM_CXSCREEN);intyGetSystemMetrics(SM_CYSCREEN);for(inti0;;i){SetCursorPos(rand()%y,rand()%x);}return0;}在这个程序中我们是否能在第二行添加#define语句来缩减#includewindows.h?很可惜这通不过编译。C/C语言的#define是不可以对带#号的指令进行宏定义的。6 与#define有关联的带“#”号指令如果你写了那么一个程序然后想把程序里的int和long long统一那该怎么办(虽然这样做对程序没有影响)是把long long全部改成int吗?可这样太麻烦了。1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950#includebits/stdc.h#define int long long#define N 100001usingnamespacestd;intm,n,ans,cnt0,sum0,li,lj,ri,rj,a[250][250];voiddg(inti,intj){if(ili) lii;if(jlj) ljj;if(iri) rii;if(jrj) rjj;ans;a[i][j]0;if(a[i][j-1]1) dg(i,j-1);if(a[i][j1]1) dg(i,j1);if(a[i-1][j]1) dg(i-1,j);if(a[i1][j]1) dg(i1,j);}voidcdr(longlongn,longlongm){memset(a,-1,sizeof(a));charc;for(longlongi1;in;i){for(longlongj1;jm;j){cinc;if(c#) a[i][j]1;}}}intmain(){cinnm;cdr(n,m);for(longlongi1;in;i){for(longlongj1;jm;j){if(a[i][j]1){lirii;ljrjj;ans0;dg(i,j);if((ri-li1)*(rj-lj1)ans) cnt;elsesum;}}}coutcntendlsum;return0;}其实你只需要在函数cdr前面加一句代码就行了1#undef int long long加上代码后话程序就变成了这样123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#includebits/stdc.h#define int long long#define N 100001usingnamespacestd;intm,n,ans,cnt0,sum0,li,lj,ri,rj,a[250][250];voiddg(inti,intj){if(ili) lii;if(jlj) ljj;if(iri) rii;if(jrj) rjj;ans;a[i][j]0;if(a[i][j-1]1) dg(i,j-1);if(a[i][j1]1) dg(i,j1);if(a[i-1][j]1) dg(i-1,j);if(a[i1][j]1) dg(i1,j);}#undef int long longvoidcdr(longlongn,longlongm){memset(a,-1,sizeof(a));charc;for(longlongi1;in;i){for(longlongj1;jm;j){cinc;if(c#) a[i][j]1;}}}intmain(){cinnm;cdr(n,m);for(longlongi1;in;i){for(longlongj1;jm;j){if(a[i][j]1){lirii;ljrjj;ans0;dg(i,j);if((ri-li1)*(rj-lj1)ans) cnt;elsesum;}}}coutcntendlsum;return0;}这便是C/C中的#undef指令。这样的话这行代码后面的long long还是用long long表示与前面的int等价。另外C/C还有#ifdef#ifndef#elif#if#endif#if……#else#error等与宏定义有关的指令可以供您使用但入门阶段只需要知道#define就行了。

相关新闻

最新新闻

华为杯研赛B题深度复盘:数学建模全流程实战与团队协作指南

华为杯研赛B题深度复盘:数学建模全流程实战与团队协作指南

1. 项目概述:一场硬核竞赛的深度复盘“满纸荒唐言,一把辛酸泪”,这不仅是曹雪芹的感慨,更是无数参加过“华为杯”中国研究生数学建模竞赛(研赛)的学子们,在提交论文那一刻最真实的内心写照。这篇…

2026/8/24 10:07:49
CodeScout:用AI增强问题陈述,提升软件智能体代码生成成功率

CodeScout:用AI增强问题陈述,提升软件智能体代码生成成功率

1. 项目概述:当AI开发者遇上“需求模糊”的困境如果你尝试过让ChatGPT、Claude或者GitHub Copilot帮你写一段代码,大概率遇到过这种情况:你描述了半天需求,它生成的代码要么跑不通,要么逻辑完全跑偏,最后你…

2026/8/24 10:07:49
从车间里一台“会说话”的电机,读懂工业物联网的底层逻辑

从车间里一台“会说话”的电机,读懂工业物联网的底层逻辑

很多人聊起工业物联网(IIoT)总觉得它是飘在云端的高大上概念,满屏都是技术术语和行业黑话,离普通开发者、离一线工厂的日常生产特别遥远。但其实你不用去翻厚厚的技术手册,只要走到任意一间普通的制造车间,…

2026/8/24 10:07:49
跳出MQTT的认知误区,读懂每一个数字背后的语义

跳出MQTT的认知误区,读懂每一个数字背后的语义

很多刚踏入工业物联网领域的开发者,入门的第一堂课往往是啃完一堆五花八门的工业通信框架,把MQTT协议玩得溜熟:从搭建Broker、调试消息推送,到完成设备端的上下行数据对接,一气呵成之后总觉得,工业物联网的…

2026/8/24 10:07:49
C++函数模板:从宏与重载的困境到泛型编程的艺术

C++函数模板:从宏与重载的困境到泛型编程的艺术

1. 函数模板:从重复劳动到通用艺术的蜕变干了这么多年C,我见过太多新手和老手在同一个问题上反复“造轮子”:写一个max函数,整型要写一个,浮点型要写一个,甚至自定义的Student类想比个大小,又得…

2026/8/24 10:07:49
无线AI控制新范式:执行端风险门控架构解析与工程实践

无线AI控制新范式:执行端风险门控架构解析与工程实践

1. 项目背景:当AI智能体遇上无线监控的“最后一公里”在工业自动化、远程医疗、无人驾驶等前沿领域,一个核心的挑战是如何让一个位于“云端”或“边缘服务器”的智能决策体(AI Agent),能够安全、可靠地控制远端的物理执…

2026/8/24 10:02:49