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