博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C/C++预定义宏
阅读量:5862 次
发布时间:2019-06-19

本文共 3171 字,大约阅读时间需要 10 分钟。

作者:酱油和醋

出处:

下面描述的宏定义,不需引用其他头文件,直接可用于代码中。特定的作用给我们提供了不少的便利。分别描述如下:
1 -- __FILE__,__LINE__,__FUNCTION__或者__func__
__FILE__:当前程序行所在源文件名称,标准C支持,该宏当做
字符串对待; 
__LINE__:当前程序行所在源文件内的行号,标准C支持,该宏当做
整形对待;
__FUNCTION__或者__func__:当前程序行所属的函数名称,C99支持(如:VC++6.0不支持),该宏当做
字符串对待; 
结合打印日志功能,这些信息将有助于调试。简单的使用方法:
//将该程序保存为test.cpp#include 
using namespace std;int main(int argc, char *argv[]){printf("FILE:%s|LINE:%d|FUNCTION:%s|%s\n", __FILE__, __LINE__, __FUNCTION__, __func__);return 0;}
执行上述程序将打印:FILE:test.cpp|LINE:8|FUNCTION:main|main 
特别说明,据参考资料中关于__func__的信息称,__func__不是一个宏,它是编译隐式声明的常量字符数组:static const char __func__[] = "function-name"。 
2 -- __DATE__,__TIME__
__DATE__:当前文件的编译日期,格式是Mmm:dd:yyyy。该宏当做
字符串对待。 
__TIME__:当前文件的编译时间,格式是hh:mm:ss。该宏当做
字符串对待。 
编译源文件时,假如该宏,可以让程序打印出编译时间,达到区分不同版本的目的。简单使用方法如下:
#include 
using namespace std;int main(int argc, char *argv[]){printf("DATE:%s|TIME:%s\n", __DATE__, __TIME__);getchar();return 0;}
执行上述程序将打印:DATE:Oct 20 2010|TIME:23:33:24。不重新编译程序的情况下,每次执行该程序打印的都将是是这个时间,而不是系统的当前时间。这个时间要区别理解下。
3 -- #line
#line用于重置由__LINE__和__FILE__宏指定的行号和文件名。比如说我们有这么一个测试程序: 
//将该程序保存为test.cpp#include 
using namespace std;int main(int argc, char *argv[]){#line 100 "baidu.cpp"printf("FILE:%s|LINE:%d\n", __FILE__, __LINE__);return 0;}
注释掉第8行代码,程序打印:FILE:test.cpp|LINE:9 
不注释第8行代码,程序打印:FILE:baidu.cpp|LINE:100 
可见:#line指定下行代码的起始行号和源文件名称,作用域到文件末尾或者再次#line的使用处。
4 -- __GUNC__
__GUNC__,是GCC编译器的预定义,表明当前GNUC编译的版本。__GNUC__ 的值表示gcc的版本,需要针对gcc特定版本编写代码时,可以使用该宏进行条件编译。 
6 -- 宏定义的"#"和"##"使用方法
"#":替换宏参数时,将其后面的宏参数转换成带引号的字符串,例如:
#define STR(s) #sint main(){std::string str = STR(abcdefg);return 0;}
C编译器在预处理代码时,第5行实际翻译成:std::string str = "abcdefg";
"##":将该符号前后的两个宏参数连接在一起,比如: 
#define PRINT(PRINT_FUNNAME, VAR) print_##PRINT_FUNNAME(VAR)int main(){PRINT(common, 5);return 0;}
C编译器在预处理代码时,第5行实际翻译成:print_common(5);
我们实际看下综合运用的例子:
//#include 
#define PRINT(fun, name, var) print_##fun(#name, var)void print_common(const std::string & name, int var){std::cout << name << ":" << var << std::endl;}void print_tofile(const std::string & name, int var){char sz_temp[1024];memset(sz_temp, 0, sizeof(sz_temp));snprintf(sz_temp, sizeof(sz_temp), "%s:%d", name.c_str(), var);FILE * fp = fopen("./log.log", "w");fwrite(sz_temp, 1, strlen(sz_temp), fp);fclose(fp);}int main(){PRINT(common, age, 5);PRINT(tofile, age, 5);return 0;}
这个代码的意思是,在主函数中以统一的调用入口"PRINT"该宏函数,通过制定不同的函数名称,将变量的名称和值打印到不同的地方,比如屏幕或者文件中。
我们使用g++ -E marco.cpp预处理命令查看下预处理后的源文件:
# 1 "marco.cpp"# 1 "
"# 1 "
"# 1 "marco.cpp"void print_common(const std::string & name, int var){std::cout << name << ":" << var << std::endl;}void print_tofile(const std::string & name, int var){char sz_temp[1024];memset(sz_temp, 0, sizeof(sz_temp));snprintf(sz_temp, sizeof(sz_temp), "%s:%d", name.c_str(), var);FILE * fp = fopen("./log.log", "w");fwrite(sz_temp, 1, strlen(sz_temp), fp);fclose(fp);}int main(){print_common("age", 5);print_tofile("age", 5);return 0;}
7 -- 参考文档&扩展阅读
1/http://blog.csdn.net/chief1985/archive/2008/07/25/2711526.aspx 
2/http://lukas06.blog.sohu.com/95352179.html

转载于:https://www.cnblogs.com/leonxyzh/archive/2013/01/11/7289131.html

你可能感兴趣的文章
dva开发一个cnode网站(2)
查看>>
Redis 的持久化与过期键
查看>>
python大佬养成计划----socket网络编程
查看>>
JavaWEB开发08——Response
查看>>
【go密码学】-Hash
查看>>
Elasticsearch实践(一):基础入门
查看>>
前端系列——小程序开发记录片
查看>>
Hydux: 一个 Elm-like 的 全功能的 Redux 替代品
查看>>
Linux磁盘分区
查看>>
[afterCode] docker 速成班 番外篇: 随机容器名
查看>>
在 Forge Viewer 里展示/隐藏构件材质
查看>>
ES6系列---块级作用域
查看>>
JQuery使用总结
查看>>
CentOS7 安装RocketMQ并测试使用
查看>>
JVM参数使用手册
查看>>
PHP设计模式-观察者模式
查看>>
ES6 - 收藏集 - 掘金
查看>>
写个vue-loading-template组件
查看>>
PHP - 收藏集 - 掘金
查看>>
函数式编程(五)
查看>>