printf 格式化 (备忘)

1 篇文章 0 订阅

man 3 printf 中间的一段, 介绍 format 参数 int printf(const char *format, ...);


   Format of the format string
       The format string is a character string, beginning and ending in its initial shift state, if any.  The format string is composed of zero or more directives: ordinary  characters
       (not  %),  which  are copied unchanged to the output stream; and conversion specifications, each of which results in fetching zero or more subsequent arguments.  Each conversion
       specification is introduced by the character %, and ends with a conversion specifier.  In between there may be (in this order) zero or more  flags,  an  optional  minimum  field
       width, an optional precision and an optional length modifier.
就是说有两类,
 1类是普通的, 原封不动的输出。
 1类是有其他意思的: conversion specifications,  开始是  %,结束是 [conversion specifier]。 中间有其他修饰的, 可选
minimum  field width, 最小字段宽度  printf ("float 2: %2.3f\n", (float) 2);
precision  精度  printf ("float 2: %2.3f\n", (float) 2);
length modifier.  printf ("size_t 2: %zi\n", (size_t) 2);

测试下解析参数


#include <assert.h>
#include <printf.h>
#include <stdarg.h>
#include <stdio.h>

#define ARG_MAX_LEN 1000

void info () {
    printf ("PA_FLAG_MASK\t\t %04hx\n", PA_FLAG_MASK);
    printf ("~PA_FLAG_MASK\t\t %04hx\n", ~PA_FLAG_MASK);

    printf ("conversion specifier\t args & ~PA_FLAG_MASK\n");
    printf ("flags\t\t\t arg & PA_FLAG_MASK\n");

    printf ("PA_INT\t\t\t %04hx\n", PA_INT);
    printf ("PA_CHAR\t\t\t %04hx\n", PA_CHAR);
    printf ("PA_STRING\t\t %04hx\n", PA_STRING);
    printf ("PA_POINTER\t\t %04hx\n", PA_POINTER);
    printf ("PA_FLOAT\t\t %04hx\n", PA_FLOAT);
    printf ("PA_DOUBLE\t\t %04hx\n", PA_DOUBLE);

    printf ("PA_FLAG_LONG_LONG\t %04hx\n", PA_FLAG_LONG_LONG);
    printf ("PA_FLAG_LONG\t\t %04hx\n", PA_FLAG_LONG);
    printf ("\n\n");
}

short int get_conversion_specifier (short pa) {
    return pa & ~PA_FLAG_MASK;
}
short int get_flag (short pa) {
    return pa & PA_FLAG_MASK;
}
void test_print_format (const char *fmt) {
    printf ("test format [%s]\n", fmt);
    int args[ARG_MAX_LEN];
    int arg_no = parse_printf_format (fmt, ARG_MAX_LEN, args);
    for (int i = 0; i < arg_no; ++i)
        printf ("\t%d arg: %x\n", i, args[i]);
}

void skip_args_impl (const char *first_arg, va_list al) {
    const char *fmt = first_arg;
    do {
        int args[ARG_MAX_LEN];
        int arg_no = parse_printf_format (fmt, ARG_MAX_LEN, args);
        if (arg_no == 0) break;
        test_print_format (fmt);

        for (int i = 0; i < arg_no; ++i) {
            short int type = get_conversion_specifier (args[i]);
            short int flag = get_flag (args[i]);
            printf ("type %hx, flag %hx\n", type, flag);
            switch (type) {
            case PA_INT:
                if (flag == PA_FLAG_LONG_LONG)
                    (void) va_arg (al, long long);
                else if (flag == PA_FLAG_LONG)
                    (void) va_arg (al, long);
                else
                    (void) va_arg (al, int);
                break;
            case PA_CHAR:
                (void) va_arg (al, int);
                break;
            case PA_STRING:
                (void) va_arg (al, char *);
                break;
            case PA_POINTER:
                (void) va_arg (al, void *);
                break;
            case PA_FLAG_LONG_LONG:
                (void) va_arg (al, long long);
                break;
            case PA_FLOAT:
                // FALLTHROUGH
            case PA_DOUBLE: 
                (void) va_arg (al, double);
                break;
            default:
                printf ("unsupport type\n");
                assert (0);
            }
        }
        fmt = va_arg (al, char *);
    } while (1);
}

void skip_args (const char *fmt, ...) {
    va_list al;
    va_start (al, fmt);
    printf ("call skip_args_impl\n");
    skip_args_impl (fmt, al);
    va_end (al);
}

int main () {
    info ();
    test_print_format ("%2.3f");
    test_print_format ("%2.3d");
    test_print_format ("%s");
    test_print_format ("%2.3f %2d %s %lld %2u");

    skip_args ("%2.3f %2d %s %lld %2u",
               (float) 2, (int) 2, "hello", (long long) 2, (unsigned) 2,
               "%2.3f %2d %s %lld %2u",
               (float) 2, (int) 2, "hello", (long long) 2, (unsigned) 2);


    return 0;
}

运行结果

PA_FLAG_MASK		 ff00
~PA_FLAG_MASK		 00ff
conversion specifier	 args & ~PA_FLAG_MASK
flags			 arg & PA_FLAG_MASK
PA_INT			 0000
PA_CHAR			 0001
PA_STRING		 0003
PA_POINTER		 0005
PA_FLOAT		 0006
PA_DOUBLE		 0007
PA_FLAG_LONG_LONG	 0100
PA_FLAG_LONG		 0200


test format [%2.3f]
	0 arg: 7
test format [%2.3d]
	0 arg: 0
test format [%s]
	0 arg: 3
test format [%2.3f %2d %s %lld %2u]
	0 arg: 7
	1 arg: 0
	2 arg: 3
	3 arg: 100
	4 arg: 0
call skip_args_impl
test format [%2.3f %2d %s %lld %2u]
	0 arg: 7
	1 arg: 0
	2 arg: 3
	3 arg: 100
	4 arg: 0
type 7, flag 0
type 0, flag 0
type 3, flag 0
type 0, flag 100
type 0, flag 0
test format [%2.3f %2d %s %lld %2u]
	0 arg: 7
	1 arg: 0
	2 arg: 3
	3 arg: 100
	4 arg: 0
type 7, flag 0
type 0, flag 0
type 3, flag 0
type 0, flag 100
type 0, flag 0


参考: http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Parsing-a-Template-String.html#Parsing-a-Template-String

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值