• 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"
    ",__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,欢迎关注

  • 相关阅读:
    tomcat目录简介
    静态链接库、动态链接库
    查看软、硬raid信息的方法
    linu流量监控
    EXT格式误删除恢复
    linux下securetty文件
    linux下快速删除大量文件
    linux路由配置负载均衡
    python代码 构建验证码
    分布式系统架构
  • 原文地址:https://www.cnblogs.com/pusidun/p/13166667.html
Copyright © 2020-2023  润新知