5-5 案例:实现PRINTLNF

每次调用 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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值