一个C语言宏展开问题
一个令人比较迷惑的问题,学C语言好多年,今天终于搞明白,记之。
-------------------------------------------------------------
#define cat(x,y) x ## y
#define xcat(x,y) cat(x,y)
cat(cat(1,2),3) //为什么不是 123?
xcat(xcat(1,2),3) //结果为什么是 123?
-------------------------------------------------------------
要解答这个问题,首先看一下预处理过程的几个步骤:
1) 字符集转换(如三联字符)
2) 断行连接 /
3) 注释处理, /* comment */,被替换成空格
4) 执行预处理命令,如 #include、#define、#pragma、#error等
5) 转义字符替换
6) 相邻字符串拼接
7) 将预处理记号替换为词法记号
在这里主要关注第4步,即如何展开函数宏。(其他步骤和本文关系不大,但对于理解预处理过程是十分重要的)宏函数替换展开,规则可简单总结如下:在展开当前宏函数时,如果形参有#(字符串化操作)或##(记号连接操作)则不进行宏参数的展开,否则先展开宏参数,再展开当前宏(就像先计算函数中的参数,然后调用函数一样)。回头看最初的问题,则两个宏展开过程如下:
-------------------------------------------------------------
cat(cat(1,2),3)
=> cat(1,2) ## 3 // cat(x,y) x##y参数前有##操作,参数不展开
=> cat(1,2)3 // K&R中说,)3 是一个不合法记号,不展开
-------------------------------------------------------------
xcat(xcat(1,2),3)
=> xcat(cat(1,2),3) //xcat(x,y) cat(x,y)参数前无#,##操作,则先展开参数
=> xcat(1 ## 2,3)
=> xcat(12,3)
=> cat(12,3)
=> 12 ## 3
=> 123
-------------------------------------------------------------
有兴趣的话,可以看下面一些宏替换问题:
-------------------------------------------------------------
#define X 3
#define Y X*2
#undef X
#define X 2
int z=Y; // z = 4
-------------------------------------------------------------
#define hash_hash # ## #
#define mkstr(a) # a
#define in_between(a) mkstr(a)
#define join(c, d) in_between(c hash_hash d)
char p[] = join(x, y); // 等同于char p[] = "x ## y";
-------------------------------------------------------------
#define connect(x) i ## x
#define connect2(x) connect(x)
#define s(a) a
#define is(a) a
int i2=2;
printf("%d/n", connect(s(1)) );/*connect的形参x是##的操作数,故不展开它对应的实参s,直接连接记号i和实参序列s(1),得到is(1),继续替换得到最后结果1*/
printf("%d/n", connect2(s(2)) );/*connect2的形参x不是##的操作数,故先展开它对应的实参s,再用展开结果2替换之,得到connect(2),继续替换得到最后结果i2*/
-------------------------------------------------------------
#define TEST(a,b) /
do {/
printf(#a "=%d/n", a); /
printf(#b "=%d/n", b); /
} while (0)
一个C语言宏展开问题的更多相关文章
- c语言 预处理的使用 宏展开下的#,##
1. #include 包含头文件 2.define 宏定义(可以理解为替换,不进行语法检查) 写法 #define 宏名 宏体 加括号 #define ABC (5+3) #define AB ...
- C宏展开的几个注意事项
前阵子仔细重新研究了一下C的宏展开.总结起来,有以下几个主要规则: 每次宏展开的结果会被重复扫描,直到没有任何可展开的宏为止. 每展开一个宏,都会记住这次展开,在这个宏展开的结果及其后续展开中,不再对 ...
- 第一个C语言编译器是怎样编写的?
首先向C语言之父Dennis MacAlistair Ritchie致敬! 当今几乎所有的实用的编译器/解释器(以下统称编译器)都是用C语言编写的,有一些语言比如Clojure,Jython等是基于J ...
- C中宏展开问题
C中宏展开问题 简单记录一下碰到的问题. #define STR(x) #x 我们知道使用上面的宏可以将x转换为字符串"x". 但是如果这样用: #define NUM 3 #de ...
- 【做中学】第一个 Go 语言程序:漫画下载器
原文地址: 第一个 Go 语言程序:漫画下载器: https://schaepher.github.io/2020/04/11/golang-first-comic-downloader 之前学了点 ...
- 你知道第一个C语言C++编译器是如何诞生的吗?
当今几乎所有的实用的编译器/解释器(以下统称编译器)都是用 C 语言编写的,有一些语言比如 Clojure,Jython 等是基于 JVM 或者说是用 Java 实现的,IronPython 等是基于 ...
- 第一个C语言程序
从第一个C语言程序了解C语言 了解关键字 了解函数 注释 C语言的执行流程 标识符 C语言的学习重难点 从第一个C语言程序了解C语言 上图是一个在控制台上显示“Hello, World!”的C语言源代 ...
- php调用一个c语言写的接口问题
用php调用一个c语言写的soap接口时,遇到一个问题:不管提交的数据正确与否,都无法请求到接口 1.用php标准的soap接口去请求 2.拼接xml数据去请求 以上两种方式都不正确 解决办法:php ...
- 机器学习(一) 从一个R语言案例学线性回归
写在前面的话 按照正常的顺序,本文应该先讲一些线性回归的基本概念,比如什么叫线性回归,线性回规的常用解法等.但既然本文名为<从一个R语言案例学会线性回归>,那就更重视如何使用R语言去解决线 ...
随机推荐
- 优雅的使用 PhpStorm 来开发 Laravel 项目
[目录] Prerequisites plugin installation and configuration 1 Ensure Composer is initialized 2 Install ...
- 使用WCF和WEBService出现配置的问题
错误代码:system.serviceModel/bindings/customBinding 处的绑定没有名称为"SMSServiceServiceSoapBinding"的已配 ...
- 一个用ASP生成html的新方法
目前已经有很多生成html的新闻系统,但是都是用的模板,本函数实现把asp页面产生的html代码保存成为一个html文件,这样就没有必要改动原来的页面就可以轻松完成一个生成html的新闻系统了.^_^ ...
- python学习第二天:数字与字符串转换及逻辑值
1.数字与字符串的转化 #1.数字转字符,使用格式化字符串: *1.demo = ‘%d’ % source *2.%d整型:%f 浮点型 :%e科学计数 ...
- 爬虫遇到取到网页为reload的问题
有的网站防采集,会在页面加上this.window.location.reload(),这时候你就会得到如下代码: <html> <head> <meta ...
- 轮子来袭 vJine.Core Orm 之 01_快速体验
vJine.Core 是.Net环境下C#类库,在其包含的众多功能中ORM功能尤为突出,现简介如下. 一.支持的数据库: SQLite, MySQL, MS SQL, Oracle. 二.使用方法: ...
- 05顺序队列_Queue--(栈与队列)
#include "stdio.h" #include "stdlib.h" #include "io.h" #include " ...
- Basic MSI silent install
Articles and post about silent install for Basic MSI, InstallScript, InstallScript MSI: Silent-mode ...
- Fire Net
Fire Net Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other) Total Subm ...
- leetcode Largest Rectangle in Histogram 单调栈
作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4052343.html 题目链接 leetcode Largest Rectangle in ...