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的方法见第一讲,结 ...
随机推荐
- linux高级应用第九章-正则表达式
笔记部分 基础正则表达式: ^ 第1个符号 ,以什么什么开头 ^m $ 第2个符号,以什么什么结尾 m$ ,还表示空行,或空格,可以用cat -An 试一下 ^$ 第3个符号,空行 ...
- 前端基础进阶(十四):es6常用基础合集
在实际开发中,ES6已经非常普及了.掌握ES6的知识变成了一种必须.尽管我们在使用时仍然需要经过babel编译. ES6彻底改变了前端的编码风格,可以说对于前端的影响非常巨大.值得高兴的是,如果你熟悉 ...
- Android_AndroidX简介&Junit4
AndroidX简介: Android 9.0(API level 28)发布时,AndroidX也作为一个新的支持库发布出来了.AndroidX时Jetpack的一部分,它包含了现有的支持库和最新的 ...
- [PHP自动化-进阶]002.CURL模拟登录带有验证码的网站
引言:继前文<模拟登录并采集数据>,大家似乎看不过瘾,这会再出一发,模拟实现带验证码网站的登录. 这篇文章主要介绍了PHP使用CURL实现对带有验证码的网站进行模拟登录的方法,可以帮助读者 ...
- Misdirection: 1靶机writeup
看下端口 nmap -A 172.16.61.131 一些坑3306无法访问,80,web2py漏洞无法利用 利用dirb遍历网站路径 得到下面命令执行漏洞 http://172.16.61.131: ...
- MySQL 可重复读,差点就我背上了一个 P0 事故!
小黑黑的碎碎念 哎,最近有点忙,备考复习不利,明天还要搬家,好难啊!! 本想着这周鸽了,但是想想还是不行,爬起来,更新一下,周更可不能断.偷懒一下,修改一下之前的一篇历史文章,重新发布一下. P0 事 ...
- 非阻塞赋值(Non-blocking Assignment)是个伪需求
https://mp.weixin.qq.com/s/mH84421WDGRb7cuU5FEFIQ Verilog的赋值很是复杂,包括: 1. Continuous assignment; 2. Pr ...
- Rocket - config - Keys & Params
https://mp.weixin.qq.com/s/Y42EWrO7IoHRD_yHD4iRLA 介绍配置项.配置值以及他们的使用方式. 参考链接: https://docs.qq.com/ ...
- jchdl - GSL实例 - DLatch(D锁存器)
https://mp.weixin.qq.com/s/c8kDgye50nKJR4tkC0RzVA D锁存器对电平敏感,当使能位使能时,输出Q跟随输入D的变化而变化. 摘自康华光<电子 ...
- 面试题: MySQL 索引失效的10大原因
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 1.建表: CREATE TABLE staffs ( id INT PRIMARY KEY AUTO_ ...