当前位置: 首页 > news >正文

C语言 宏嵌套的展开规则

C语言中,宏是在预编译时用宏体内容“文本替换”代码中的宏名的。

先讲一些宏嵌套的展开规则:

  1. 一般的展开规律像函数的参数一样:先展开参数,再分析函数,即由内向外展开;
  2. 当宏中有#运算符的时候,不展开参数;
  3. 当宏中有##运算符的时候,先展开函数,再分析参数;
  4. ##运算符用于将参数连接到一起,预处理过程把出现在##运算符两侧的参数合并成一个符号,注意不是字符串;

“#”和“##”的使用规则:

“#”是将宏参数转换为字符串。不管该参数宏什么,即“原貌”用字符串显示出来。即将宏参数用双引号“”包裹起来形成一个字符串。例如:

代码语言:javascript

AI代码解释

#define T(x) #x int temp = 10; cout << T(temp) << endl; //输出 temp 而不是 10 // T(temp) -> "temp" (将宏参数用双引号包含起来形成一个字符串)

“##”被称为连接符(concatenation),把宏参数与之前的token(参数/字符串空格等)连接起来。例如:

代码语言:javascript

AI代码解释

#define T(x) x##[2] int a[5] = {1,2,3,4,5}; cout << T(a) << endl; //输出 3 即 a[2]

宏的常见展开错误:

代码语言:javascript

AI代码解释

// 1. 宏参数在宏体中未加括号包裹起来 #define T(a) a*10 int a = 1; cout << T(a+1) << endl; //输出 11 而非20 // 2. 整个宏体内容未加括号包裹起来 #define T(x) x+1 cout << 10*T(1) << endl; //输出 11 而非20

解决办法:

  1. 在宏定义中,将参数加上括号,这样在替换时保证括号内的表达式优先运算。
  2. 利用括号将整个宏定义的内容括起来,保证整个宏定义中的表达式优先运算。

宏嵌套:

宏嵌套是宏使用的难点,也是易错点。下面我将宏嵌套的展开规则用流程图来说明一下:

注意:上图中的 2 和 3 是条件或,只要满足一个条件就会进入流程 5。

下面举例说明:

代码语言:javascript

AI代码解释

// example 1 #include <cstdio> #define TO_STRING2(x) #x #define TO_STRING1(x) #x #define TO_STRING(x) TO_STRING1(x) #define PARAM(x) #x #define ADDPARAM(x) INT_##x int main() { const char *str = TO_STRING(PARAM(ADDPARAM(1))); printf("%s\n", str); //输出: "ADDPARAM(1)" str = TO_STRING2(PARAM(ADDPARAM(1))); printf("%s\n", str); //输出: PARAM(ADDPARAM(1)) return 0; }

上例中两个嵌套宏的展开流程如下:

代码语言:javascript

AI代码解释

TO_STRING(PARAM(ADDPARAM(1))) -> 展开 PARAM:TO_STRING("ADDPARAM(1)") -> 展开 TO_STRING:TO_STRING1("ADDPARAM(1)") -> 展开 TO_STRING1:"\"ADDPARAM(1)\"" TO_STRING2(PARAM(ADDPARAM(1))) -> 展开 TO_STRING2:"PARAM(ADDPARAM(1))"

代码语言:javascript

AI代码解释

// example 2 #include <cstdio> #define TO_STRING2(x) a_##x #define TO_STRING1(x) #x #define TO_STRING(x) TO_STRING1(x) #define PARAM(x) #x #define ADDPARAM(x) INT_##x int main() { const char *str = TO_STRING(TO_STRING2(PARAM(ADDPARAM(1)))); printf("%s\n", str); //输出: a_PARAM(INT_1) return 0; }

上例中嵌套宏的展开流程如下:

代码语言:javascript

AI代码解释

TO_STRING(TO_STRING2(PARAM(ADDPARAM(1)))) -> 展开 TO_STRING2:TO_STRING(a_PARAM(ADDPARAM(1))) //注意此次展开后,PARAM宏名被破坏了,变成了a_PARAM不再是有效的宏名了 -> 展开 ADDPARAM:TO_STRING(a_PARAM(INT_1)) -> 展开 TO_STRING:TO_STRING1(a_PARAM(INT_1)) -> 展开 TO_STRING1:"a_PARAM(INT_1)"
http://www.jsqmd.com/news/732256/

相关文章:

  • 基于DINOv3、Swin Transformer、FastViT、ResNet的场景识别模型
  • 从`/proc/interrupts`输出看网络性能:以Realtek RTL8125网卡的中断风暴排查为例
  • 鑫豆娘豆腐店加盟——正规品牌护航,开一家火一家的刚需创业好项目 - 奔跑123
  • 把 SNC PSE 创建对,别让 STRUST 成为你上线前最后一个拦路虎
  • 雀魂牌谱屋完全指南:3步开启你的麻将数据分析之旅
  • 上海写字楼安保公司哪家好?2026正规商场/园区安保外包公司实力权威推荐 - 栗子测评
  • 从OBS插件到采集卡:聊聊那些伪装成‘正经软件’的AI自瞄,以及反作弊如何‘抓鬼’
  • 配置路径 + 数据路径架构
  • 2025届学术党必备的六大降重复率网站推荐
  • 【flutter for open harmony】第三方库Flutter 鸿蒙版 物流追踪 实战指南(适配 1.0.0)✨
  • 如何用3种方法让Mem Reduct显示中文界面?技术选型与实施指南
  • 2026江苏/南京安保服务哪家好?本地学校/商场安保服务商精选榜单 - 栗子测评
  • 企业如何利用Taotoken统一管理多个AI模型的API密钥与访问权限
  • 企业内如何构建安全可控的大模型API调用与管理体系
  • 在 Node.js 服务中集成多模型能力借助 Taotoken 统一 API 调用
  • GPT-5.5写文案、改稿、做大纲,写作全流程实测
  • 为什么85%的中文玩家都在寻找MASA模组汉化包?终极解决方案来了
  • 海外市场“可解释金融智能体”受关注,国内IT服务商如何参与竞争
  • CL9095 500mA输出可调线性稳压器
  • ComfyUI-Impact-Pack终极指南:解锁AI图像精细化处理的完整工作流
  • 把 ABAP 平台上的 SNC 真正配通,使用 SAP Cryptographic Library 完成 PSE、密钥对与应用服务器落地
  • 18年GitHub老用户因平台故障频发迁出项目,直言:若改进仍愿回归
  • 如何在10分钟内搭建高效的PlantUML Server?[特殊字符]
  • 安卓基础之《(29)—消息机制与异步任务》
  • 2026年5月最新宝珀官方售后网点核验报告(含迁址/新开)|亲测全流程记录 - 亨得利官方服务中心
  • 从零到上线:手把手教你用Vue3+OpenLayers搭建一个企业级GIS管理系统(兼容IE11)
  • Maccy:重新定义macOS剪贴板管理的工作流优化方案
  • 2025届毕业生推荐的十大降AI率网站横评
  • Windows 11任务栏拖放修复:终极免费解决方案完全指南
  • 从设计到售后:如何把FMEA、FTA和FRACAS串起来,打造产品可靠性闭环