C语言Printf输出格式美化

C语言Printf输出格式美化

在项目开发中,测试功能时使用Printf()调试代码应该是最为简单实用的方法之一了,但关于对输出格式美化方面的介绍内容较少,在此本人结合实际开发中使用的方法和网上查阅的资料做一点整理,希望能帮助到有需要的人.

Printf函数简介

printf()函数,相信每个人都不陌生,很多人的C语言开发之路都是从一句Hello word开始的.printf()的函数原型如下:
int printf ( const char * format, ... );
printf将 format 指向的 C 字符串写入标准输出 (stdout)。如果 format 包含格式说明符(以 % 开头的子序列),则 format 后面的附加参数将被格式化并插入到结果字符串中,替换其各自的说明符
格式说明符遵循此原型:%[flags][width][.precision][length]specifier,其中末尾的说明符是最重要的部分,因为它定义了其对应参数的类型和解释,并且不可省略,而剩余的子说明符部分可以做省略,关于格式说明符和其子说明符的关系请参考此链接C Printf说明学习,下面简略介绍一下子说明符。
[flags]:

  • 若为+则在输出中强制加上+.如"+3".
  • 若为-,控制输出左对齐,默认为右对齐。

[with]:

  • 若为数值,则表示要打印的最小字符数。如果要打印的值短于此数字,则结果将用空格填充。即使结果较大,也不会截断该值。
  • 若为*,则表示宽度未在格式字符串中指定,而是作为必须格式化的参数前面的附加整数值参数指定。

[.precision]:

  • 对于整数说明符(d、i、o、u、x、X):精度指定要写入的最小位数。如果要写入的值短于此数字,则结果将用前导零填充。即使结果较长,也不会截断该值。精度为 0 表示不会为值 0 写入任何字符。
  • 对于 a、A、e、E、f 和 F 说明符:这是小数点后要打印的位数(默认情况下为 6)。
  • 对于 g 和 G 说明符:这是要打印的最大有效位数。
  • 对于 s:这是要打印的最大字符数。默认情况下,将打印所有字符,直到遇到结尾的空字符。

[length]:

  • 长度子说明符修改数据类型的长度。

输出格式控制

在实际开发中,我们可能需要对字符串,浮点数或者整型变量做输出格式化控制,结合上文中提到格式说明符与子说明符的关系,下面简单演示下如何使用子说明符控制复杂格式输出:

//test_printf.c
#include<stdio.h>

int main(void)
{
	//1. 字符串长度控制
	char *string = "abcdefghijk";
	printf("String: %3s %30.30s %-30.30s %-3.3s\n" ,
			string ,string , string ,string );
			  
	//2. 整数长度控制
	int a = 123456789 ;
	printf("Int: %5d %20.20d %-20.20d %-2.2d\n" ,  a , a , a , a );
			 
	//3. 浮点数长度控制
	double b = 1.23456789;
	printf("Double %3f %30.30f %-30.30f %3.3f \n" , b , b , b ,b);

	return 0;
}

编译运行结果如下:
运行结果
可以看到,和上文中描述的子说明符作用一致:

  • 对整数而言,由于实际长度(10)小于[precision]值,前面被补零,实际长度(10)没有被[width]项限制
  • 对浮点数而言,精度被指定为[precision]值,[precision]值为30时,补全精度为30,[precision]值为3时,截断输出精度为3
  • 对字符串而言,分别展示了字符串的左右对齐,及[precision]值指定下的字符串输出,小于[precision]值时全部输出,大于[precision]值时截断为[precision]值。

制表符作用原理

\t制表符在printf中使用的较少,可能大家都比较陌生,它主要的作用是控制输出字符,使输出字符%8 = 0,能用于实现列补全.简单展示下用法如下:

//test_print_t.c
#include<stdio.h>

int main(void)
{
	char *stringa = "12" ;
	char *stringb = "123" ;
	char *stringc = "12345" ;
	char *stringd = "1" ;
	printf("%s\t%s\t%s\t%s\t\n",stringa ,stringb ,stringc ,stringd);
}

编译运行结果如下可以看到,每个字符串的输出都被补全到8的倍数.
在这里插入图片描述
可以认为它补全空格的计算公式如下:
t = 8 - string_len % 8

输出格式美化

结合上文的制表符和格式说明符相关的知识,就不难做到本文提到的输出格式美化了.大致分为以下四个步骤:

  • 根据数据内容,定义数据最大长度
  • 根据数据形式,定义对应模板
  • 使用子说明符及制表符实现模板
  • 填充数据到输出模板

下面假设我们需要提供一个输出格式为:

****************
**	XX : XX	**
****************

下面分别举例说明多行输出和单行输出的做法。

单行输出美化的例子:

由于只需要对单行输出进行美化,就可以取巧一下,利用[width]参数中的*(宽度未在格式字符串中指定,而是作为必须格式化的参数前面的附加整数值参数指定),只对核心的输出格式做限制,将其余的整行的长度等等,完全交由代码自动生成.代码如下:

//test_format_printf.c 
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int get_line_length(char * string1 , char * string2)
{
    int string1_len = strlen(string1);
    int string2_len = strlen(string2);
    int line_len = 8 + string1_len + (8 - (string1_len % 8)) + 8 + string2_len + (8 - (string2_len % 8)) + 2;
    printf("Get  string1_len %d ,string2_len %d , line_len %d\n" ,
        string1_len , string2_len , line_len);
    
    return line_len;
}

char *build_line(int line_length , char format)
{
    int i = 0;
    line_length = line_length + 1;//'\0'
    char *buffer_line = (char *)malloc(line_length);

    snprintf(buffer_line , line_length , "%0*d" , line_length , 0);
    while(buffer_line[i] == '0')
    {
        buffer_line[i++] = format;
    }

    printf("Build Buffer_line \n%s \n" , buffer_line);

    return buffer_line;
}

int main(int argc , char *argv[])
{
    if(argc != 3)
    {
        printf("Usage: %s <string1> <string2>",argv[0]);
        exit(-1);
    }

    int line_length = get_line_length(argv[1] , argv[2]);
    char *buffer_line = build_line(line_length , '*');

    printf("%s \n" , buffer_line);
    printf("**\t%*.*s\t:\t%*.*s\t**\n", (int)strlen(argv[1]) , (int)strlen(argv[1]) , argv[1] ,
            (int)strlen(argv[2]) , (int)strlen(argv[2]) , argv[2] );
    printf("%s \n" , buffer_line);
   	free(buffer_line);
   	
    return 0;
}

在这里插入图片描述
编码后可以看到运行结果如上图,对于任意输入字符串,都能很好的达成目标格式.

多行输出美化的例子

对多行输出进行美化时,就不能取巧了,需要事先确认数据输入中的最大值,然后定义好最长行宽,对数据做截断,代码如下:

//test_format_printf.c 
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

char *build_line(int line_length , char format)
{
    int i = 0;
    line_length = line_length + 1;//'\0'
    char *buffer_line = (char *)malloc(line_length);

    snprintf(buffer_line , line_length , "%0*d" , line_length , 0);
    while(buffer_line[i] == '0')
    {
        buffer_line[i++] = format;
    }

    printf("Build Buffer_line \n%s \n" , buffer_line);

    return buffer_line;
}

int main(int argc , char *argv[])
{
    if(argc < 3)
    {
        printf("Usage: %s <string1> <string2> ... ",argv[0]);
        exit(-1);
    }

    printf("Get argc %d \n" , argc);

    //int line_length = get_line_length(argv[1] , argv[2]);
    char *buffer_line = build_line(50 , '*');
    printf("%s \n", buffer_line);

    for(int i=1 ; i < argc ; i+=2)
    {
        int j = i+1;
        printf("%s \n", buffer_line);
        printf("**\t%12.12s\t:\t%12.12s\t**\n", argv[i] , argv[j]);    
        //8 + 12 + 4 + 8 +12 +4 + 2 = 50
    }

    printf("%s \n", buffer_line);
    free(buffer_line);
    
    return 0;
}

编译运行结果如下;
在这里插入图片描述
代码很简单没什么多讲的,唯一需要注意的是正确计算含制表符在内的输出长度( 此处输出的右对齐的,如果想变成左对齐,修改**\t%12.12s\t:\t%12.12s\t****\t%-12.12s\t:\t%-12.12s\t**即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值