每次调用 printf,都需要自己书写一个换行符,那能否写个自定义的 printlnf ,其具有自动换行的功能呢?
1. 利用变长参数实现 PRINTLNF
注意这个变长参数和 4-4 的变长参数有些许不同,那个传入的第一个参数为 args_count,即变长参数的数目,这里面传入的第一个参数为 const char* format,即 printf("x: %d", x) 其中的 "x: %d"。
#include <stdarg.h>
#include <stdio.h>
/**
*
* @param format 输出的语句,例如 printf("x: %d", x) 其中的 "x: %d"
* @param ... 对应第一个参数中的各种变量
*/
void Printlnf(const char* format, ...){
// 1. 获取第二个参数里所有的变量
va_list args;
// 2. args 一块空间,format 一块空间,对齐一下
va_start(args, format);
// 3. 对齐之后,可以打印了
vprintf(format, args);
printf("\n"); // 想要的换行功能
}
2. 利用宏实现 PRINTLNF
宏实现 PRINTLNF 本质上就是在宏上对 printf() 函数进行改造,在每次输入之后多给它加个换行。
通常 printf() 函数格式为 printf("x:%d", x),所以共分两块。第一块是 "x:%d",使用 format 参数替代,这个是用户传的固定长度。第二块是 x 等变量,实际上是变长参数,因为不清楚具体有多少个 x 这样的变量。所以需要用到 __VA_ARGS__,用来获取变长参数。
// ## 是编译器自带的功能,可以在后面没有参数的情况下,把这个多余的逗号删除
#define PRINTLNF(format, ...) printf(format"\n", ##__VA_ARGS__)
int main(){
PRINTLNF("Hello %d");
PRINTLNF("World %d");
return 0;
}
其实有两个小问题:
Q: printf(format"\n"),如果 format 为 "hello",那么 printf(format"\n") 实际为 printf("hello""\n")。此时存在一个问题,正常情况下,我们输出应该写为 printf("hello \n") 这样的形式,而 printf("hello""\n") 能正常输出吗?
A: 答案是可以,原因是两个双引号碰到一起会转换为一个空格。即 "hello""\n" 等同于 "hello \n"。
Q: 正常情况下,PRINTLNF("x: %d", x) 这种形式的输出是没问题的。但如果在使用 PRINTLNF时,仅仅是 PRINTLNF("hello"),会是什么结果?直接替换之后就是 printf("hello""\n",) 注意此处代码内部是多了一个逗号的,因为后面没有参数,所有 __VAR_ARGS__ 是不存在的。
A: 解决方法是 ##__VA_ARGS__,添加 ## 符号。## 是编译器自带的功能,可以在后面没有参数的情况下,把这个多余的逗号删除。
3. 利用宏实现打印输出的定制化语句格式
“x: 3” 这种形式的输出,该如何定义?
这种形式的注意点只有一个,那就是变量的名称如何获取,即编译器如何得知是 x: 3 而不是 y: 3。所以需要借助 # 来实现。宏里面设定参数 param,#param 则可以直接获取到变量的真正名称,如下例:
// #param 获取该变量的名称
#define PRINT_INT(param) printf(#param": %d", param)
int main(){
int x = 3;
PRINT_INT(x); // x: 3
return 0;
}
文件名 + 函数名 + 代码行号 + “#param: %d” 的输出格式,该如何定义?例如, (E:\project_c\C_Master\Chapter5\05.printlnf.c:31) main : x: 3
利用宏提供的获取文件名的参数 __FILE__,获取函数名的参数 __FUNCTION__,获取代码行号的参数 __LINE__ 即可实现此功能。
#define PRINTLNF(format, ...) printf("(%s %s %d): "format"\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
// (E:\project_c\Chapter05\05.printlnf.c main 40): x: 2
PRINTLNF("x: %d", x);