C/C++宏中#的用法以及多重宏的展开过程

  1. 前言

C/C++中宏定义有#最常见的用法就是用在宏定义语句的开头(如#define、#ifdef等),用来标识一个宏定义语句。除此之外,#还有两个比较重要的用法:

  • "#" 用来将标识符字符串化

  • "##" 连接两个标识符

下面就上面的两个作用,具体展开讲一讲。

  1. “#”标识符转化为字符串

“#” 可以在宏定义中将一个标识符转化为一引号字符串。

# TO_STR(ARG) #ARG   // 将参数转化为字符串,例如:
TO_STR(time) 将转化为"time"
TO_STR(a)  将转化为"a"

在一些打印中经常见到这种用法,举个例子如下:

#include <iostream>
# define LOG(ARG) cout << #ARG << " = " << ARG << endl;
using namespace std;
int main()
{
    int a = 1;
    int b = 2;
    LOG(a+b);
    return 0;
}

上面的打印结果如下:

a+b = 3

这个例子中,"#"的作用就是将a+b作为整体转化为字符串。注意,“#”将标识符转化为字符串,必须是在宏定义中,如果不是宏定义语句中,是不可以的。下面的语句是得不到上面的效果的。

#include <iostream>
using namespace std;
int main()
{
    int a = 1;
    int b = 2;
    // #a+b 是不能将a+b转化为字符串的
    cout << #a+b << " = " << a+b << endl;     
    return 0;
}
  1. "##"连接两个标识符

"##"用于在宏定义中连接两个标识符。常常用于生成一系列结构化相同代码。

#define PARAMS(TYPE, ARG) TYPE TYPE##_##ARG
PARAMS(int, cellnum); // 相当于 int int_cellnum;
PARAMS(double, salary); // 相当于 double double_salary;
  1. 多重宏的展开顺序以及需要注意的地方

如果是多重宏,那么需要按照顺序逐层展开。

#define ARGS 1,2,3

#define MACROFUNC_OUTER(PARAMS) MACROFUNC_INNER(PARAMS)
#define MACROFUNC_INNER(A,B,C) A + B + C

int a = MACROFUNC_OUTER(ARGS);
// 上面的宏MACROFUNC_OUTER(ARGS)最终会展开为:
1 + 2 + 3
// 具体展开过程为:
第一步:MACROFUNC_OUTER(ARGS) -> MACROFUNC_INNER(ARGS)
第二步:由于ARGS仍然为一个宏,可以继续展开,知道不能展开为止,故
    MACROFUNC_INNER(ARGS) -> MACROFUNC_INNER(1, 2,3)
第三步:MACROFUNC_INNER(1,2,3) -> 1 + 2 + 3

需要特别注意的是,遇到"#"以及"##"会停止展开。

// test.cpp
#define ARG1 prefix_
#define ARG2 suffix
#define CAT(A, B) A##B
// 那么下面的式子展开结果是什么呢?prefix_suffix ?
CAT(ARG1, ARG2);

使用预处理命令进行处理:g++ -E test.cpp -o test.ii, 然后使用vim查看test.ii,结果如下:

可以看到,上面的展开并没有展开为像我们预期的那样:prefix_suffix

这是因为,在宏展开过程中遇到"#"、"##"就会停止展开。对上面的展开过程作一个分析:

CAT(ARG1, ARG2)首先展开为 ARG1##ARG2, 由于在这一步展开遇到"##",于是就不会进一步
展开ARG1以及ARG2了。

为了解决上面的问题,可以增加一个中间层:

// test.cpp
#define ARG1 prefix_
#define ARG2 suffix
#define CAT(A, B) CAT(A, B)
#define XCAT(A, B) A##B
// 那么下面的式子展开结果是什么呢?prefix_suffix ?
CAT(ARG1, ARG2);

增加一个中间层之后,CAT(ARG1, ARG2)就可以顺利展开为prefix_suffix了:

CAT(ARG1, ARG2)首先展开为 XCAT(ARG1,ARG2),展开到这一步时,由于没有遇到"#"以及"##",那么
宏参数ARG1以及ARG2会进一步展开:ARG1 -> prefix_   ARG2 -> suffix,得到:
XCAT(prefix_, suffix) —> prefix_suffix
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值