C语言宏技巧 X宏
前言
本文介绍下X宏的使用
首先简单介绍下宏的几种用法
#define STRCAT(X,Y) X##Y
#define _STR(X) #@X
#define STR(X) #X
#define Log(...) {printf(__VA_ARGS__);}
/*
* x##y 拼接xy
* #@x 单引号包裹'x'
* #x 字符串化,双引号包裹"x"
* __VA_ARGS__会扩展参数...
*/
ANSI C标准中有几个标准预定义宏(也是常用的):
LINE:在源代码中插入当前源代码行号;
FILE:在源文件中插入当前源文件名;
DATE:在源文件中插入当前的编译日期
TIME:在源文件中插入当前编译时间;
STDC:当要求程序严格遵循ANSI C标准时该标识被赋值为1;
__cplusplus:当编写C++程序时该标识符被定义。常常被用来判断编译器是否符合C++11,C++14等标准,方便运用新特性
编译器在进行源码编译的时候,会自动将这些宏替换为相应内容。
举个例子大家体会下
#define log_err(M,...) fprintf(stderr,"%s %s [ERR]"M"\n",__FILE__,__LINE__,##__VA_ARGS__)
X宏
我们首先看一个日志系统的场景
enum LogLevel {DEBUG,INFO,WARN,ERROR,UNKNOW=-1};
string getLogLevel(LogLevel level) {
switch(level) {
case DEBUG:
return "DEBUG";
break;
case INFO:
return "INFO";
break;
case WARN:
return "WARN";
break;
case ERROR:
return "ERROR";
break;
default:
return "UNKNOW";
}
}
我们定义了一个结构体,表示日志级别。然后定义了一个函数,返回一个字符串,用于获取日志级别对应的名称。
例子比较简单,但我们发现,这个代码有“重复”的部分。case的每个条件的写法是相似。既然格式相同,那么我们就可以简化:
#define X(name) \
case name: \
return #name; \
break;
string getLogLevel(LogLevel level) {
switch(level) {
X(DEBUG)
X(INFO)
X(WARN)
X(ERROR)
default:
return "UNKNOW";
}
}
前面也说过了,#name是字符串化,name如果是INFO的话,#name就会转化成"INFO"
看上去代码已经清爽多了。为避免其他地方也用到X宏,我们可以在使用完毕立刻undef掉,宏就写在函数内,使代码更加紧凑,改进后如下:
string getLogLevel(LogLevel level) {
switch(level) {
#define X(name) \
case name: \
return #name; \
break;
X(DEBUG)
X(INFO)
X(WARN)
X(ERROR)
#undef X
default:
return "UNKNOW";
}
}
这样代码就紧凑多了。至于为什么这种宏叫X没考究过,可能是约定俗成的习惯吧。
最后留个思考,getLogLevel能不能也用X宏去实现?
提示:不用函数,直接用一个const char*[]数组去返回日志级别对应的字符串
答案参考如下:
#define mapLogLevel \
X(DEBUG, "DEBUG") \
X(INFO, "INFO") \
X(WARN, "WARN") \
X(ERROR, "ERROR") \
X(UNKNOW, "UNKNOW")
#define X(a, b) a,
enum LogLevel { mapLogLevel };
#undef X
#define X(a, b) b,
const char* strLogLevel[] = { mapLogLevel };
#undef X
int main(){
LogLevel level=INFO;
cout<<strLogLevel[level]<<endl;
return 0;
}
本文章同时更新微信公众号pusidun,欢迎关注

C语言宏技巧 X宏的更多相关文章
- C奇淫技巧,——宏神奇
一个.宏列表 当这个问题面临: 有一个标志变量.位代表对应的含义. 我们须要提供一组函数来訪问设置这些位.可是对于每一个标记位的操作函数都是相似的.若有32个位,难道要搞32套相似的操作函数么? 你或 ...
- Linux C编程学习之C语言简介---预处理、宏、文件包含……
C的简介 C语言的结构极其紧凑,C语言是一种模块化的编程语言,整个程序可以分割为几个相对独立的功能模块,模块之间的相互调用和数据传递是非常方便的 C语言的表达能力十分强大.C语言兼顾了高级语言和汇编语 ...
- C语言 预处理二(宏定义--#define)
//#define 宏定义(宏定义一般大写) //知识点一-->#define的作用域:从#define开始,从上往下,如果遇到#undef就到#undef处结束,如果没有就是作用于当前整个文件 ...
- C语言宏定义和宏定义函数
要写好C语言,漂亮的宏定义是非常重要的.宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等. 在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定 ...
- 一起talk C栗子吧(第一百二十四回:C语言实例--内置宏)
各位看官们,大家好,上一回中咱们说的是显示变量和函数地址的样例,这一回咱们说的样例是:内置宏.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在编译程序的时候,假设有语法错误,编译器就 ...
- C语言面试题分类->宏定义
1.写一个“标准”宏,这个宏输入两个参数并返回较小的一个 答:#define MIN(x, y) ((x)<(y)?(x):(y))//注意x,y要加括号,因为x,y如果有复合运算会出现问题. ...
- C语言学习笔记 函数式宏
不学C光搞PHP不知道还有这种东西-函数式宏,宏前面学过了Macro,编译器在对代码进行编译时会对宏表达式进行展开替换,这样宏就起到了全局变量的作用,这里函数式宏也是类似,编译器进行编译时按函数表达是 ...
- C 语言常用方法技巧
C语言常用方法技巧 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !impor ...
- Excel VBA(宏):添加宏
写在前面: .编写宏,打开VBA,双击ThisWorkbook对当前工作薄进行编写宏:双击Sheet1,对整个sheet编写宏: 或者创建模块,在模块里,编写.调试代码. 打开VBA的方法见第一讲,结 ...
随机推荐
- ELK-日志管理平台
elk日志收集工具 1.日志在工作当中的重要性 1 分析日志的意义: 2 1.分析日志监控系统运行的状态 3 2.分析日志来定位程序的bug 4 3.分析日志监控网站访问流量 ...
- 百万年薪架构师一文整理RabbitMQ、ActiveMQ、RocketMQ、Kafka
一般来说,大型应用通常会被拆分成多个子系统,这些子系统可能会部署在多台机器上,也可能只是一台机器的多个进程中,这样的应用就是分布式应用.在讨论分布式应用时,很多初学者会把它和集群这个概念搞混,因为从部 ...
- LM NTML NET-NTLM2理解及hash破解
LM Windows Vista / Server 2008已经默认关闭,在老版本可以遇到,但根据windwos的向下兼容性,可以通过组策略启用它(https://support.microsoft. ...
- 泛微 e-cology远程代码执行漏洞
影响版本:泛微 e-cology<=9.0 漏洞分析: 问题出现在 resin 下 lib 中的 bsh.jar 文件里,问题类 bsh.servlet.BshServlet,可 doGet 方 ...
- Spring boot Sample 008之spring-boot-logback
一.环境 1.1.Idea 2020.1 1.2.JDK 1.8 二.目的 spring boot 整合log4j2 二.步骤 2.1.点击File -> New Project -> S ...
- Alpha冲刺 —— 5.1
这个作业属于哪个课程 软件工程 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 Alpha冲刺 作业正文 正文 github链接 项目地址 其他参考文献 无 一.会议内容 1.展 ...
- 【HBase】rowkey、索引表设计
总订单数1亿条 ->订单id,用户id,商品id集合,订单时间,订单完成时间,订单状态: HBase表设计: 主表 -> Rowkey: 用户ID_时间戳 列簇:info 索引表 -> ...
- SpringBoot 集成 Mybatis(三)
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 1.增加持久化层 <dependency> <groupId>mysql< ...
- 用python实现汉诺塔问题
一.用动画实现汉诺塔问题: import turtle class Stack: def __init__(self): self.items = [] def isEmpty(self): retu ...
- Java实现 LeetCode 406 根据身高重建队列
406. 根据身高重建队列 假设有打乱顺序的一群人站成一个队列. 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数. 编写一个算法来重建这个队列. ...