C自带的常用的“std::cout”和“printf()”之类作为log输出显然不是一个好的方法,笔者在学习《(C11)深入理解C11:C2011新特性解析与应用》的教程中,抽出如下的代码,在轻量级调试中是一个不错的选择。
在 C99 标准中,程序员可以使用变长参数的宏定义。变长参数的宏定义是指在宏定义中 参数列表的最后一个参数为省略号,而预定义宏 __VA_ARGS__ 则可以在宏定义的实现部分替换省略号所代表的字符串。比如:
#define PR(...) printf(__VA_ARGS__)
就可以定义一个 printf 的别名 PR。事实上,变长参数宏与 printf 是一对好搭档。我们可以看如下代码清单所示的一个简单的变长参数宏的应用。
#include <stdio.h>
#define LOG(...) {\
fprintf(stderr,"%s: Line %d:\t", __FILE__, __LINE__);\
fprintf(stderr, __VA_ARGS__);\
fprintf(stderr,"\n");\
}
int main() {
int x = 3;
// 一些代码 ...
LOG("x = %d", x); // 2-1-5.cpp: Line 12: x = 3
}
// 编译选项 :g++ -std=c++11 2-1-5.cpp
如上代码清单,定义 LOG 宏用于记录代码位置中一些信息。程序员可以根据 stderr 产生的日志追溯到代码中产生这些记录的位置。引入这样的特性,对于轻量级调试,简单的 错误输出都是具有积极意义的。
注意在使用“#define”进行的宏定义的过程中,换行符是宏定义结束的标志。
宏定义分为无参数宏定义和带参数宏定义两种。
无参数的宏定义的一般形式为:"#define 标识符 字符序列",比如:
#define PI 3.1415926
则在定义它们的源程序文件中,凡定义之后出现的单词PI将用3.1415926替代之。
在宏定义的#
之前可以有若干个空格、制表符,但不允许有其它字符。宏定义在源程序中单独另起一行,换行符是宏定义的结束标志。如果一个宏定义太长,一行不够时,可采用续行的方法。续行是在键人回车符之前先键入符号"\
"。注意回车要紧接在符号"\
"之后,中间不能插入其它符号。
如有必要,宏名可被重复定义。被重复定义后,宏名原先的意义被新意义所代替。
通常,无参数的宏定义多用于定义常量。程序中统一用宏名表示常量值,便于程序前后统一,不易出错,也便于修改,能提高程序的可读性和可移植性。特别是给数组元素个数一个宏定义,并用宏名定义数组元素个数能部分弥补数组元素个数固定的不足。
注意:预处理程序在处理宏定义时,只作字符序列的替换工作,不作任何语法的检查。如果宏定义不当,错误要到预处理之后的编译阶段才能发现。宏定义以换行结束,不需要分号等符号作分隔符。
相关文章:《C++数据类型及各种形式的输入输出汇总》
致谢
(加)Michael Wong IBM XL编译器中国开发团队《(C11)深入理解C11:C++ 11新特性解析与应用 迷你》