虽然C++提供了iostream,虽然printf有各种缺点,但它仍然是我最常用的输出函数,简单,清晰。即使是这样一个常用的函数,也有一些不太为人所广为知道的小技巧,此处记录两则:
1. 对于 size_t 类型的数据,用什么转换字符来格式化?
int 用 %d, unsigned 用 %u,但对于size_t来说,不论用 %d 还是 %u编译器都可能会产生警告,而且这样也不是可移植的方法。C++中对size_t正确的转换字符是 %zu。参考如下stackoverflow上的问答:
Clean code to printf size_t in C++
http://stackoverflow.com/questions/1546789/clean-code-to-printf-size-t-in-c-or-nearest-equivalent-of-c99s-z-in-c
2. 检查格式化字符串中的转换字符和参数是否匹配。
printf是可变参数的函数,如果格式化字符串中的转换字符的个数和其后所提供的参数个数不一致,或者类型不匹配,可能会导致未定义行为,表现形式可能是得到奇怪的输出结果或者是内存错误,也有可能暂时没有影响。为了减少这种错误,gcc提供了一个开关 -Wformat,帮助检测这类错误并产生警告。-Wall 会默认打开此开关。
比如有如下代码文件 foo.cc
用 g++ -Wall foo.cc 编译,会出现警告 warning: too few arguments for format,如此能够更容易地发现此类错误。
实际的情况可能会复杂一些,比如如果自己定义了一个具有和printf类似行为的函数myprintf,如何通知gcc也对myprintf进行格式化串的检查呢?答案是在声明myprintf的时候用gcc提供的 function attribute,如下
__attribute__ ((format (printf, 2, 3))) 通知gcc myprintf有类似printf的行为,其中myprintf的第二个参数是格式化字符串,从第三个参数开始是被格式化的变量,注意这里的编号从1开始。
如果myprintf是类成员函数,请注意它的第一个参数是隐含的this指针,在指定格式化字符串和变量的的编号是需要把this也算进去。
参考:
http://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Function-Attributes.html#Function-Attributes