The width and precision formatting parameters may be omitted, or they can be a fixed number embedded in the format string, or passed as another function argument when indicated by an asterisk "*
" in the format string. For example printf("%*d", 5, 10)
will result in " 10
" being printed, with a total width of 5 characters, and printf("%.*s", 3, "abcdef")
will result in "abc
" being printed.
----------------------------------以上内容是11月21日更新,来自wikipedia------------------------------------------------------------
今天遇到一个从来没有遇到过的很神奇的表达式——
printf("%*d",5,10);
printf("%d",10);这谁都知道,打印整形数据10,完事,但是。。。但是如果%后面跟了个*捏?而且有对应的参数是个神马情况捏?
事实是这里的*对应的参数,也就是例子里面的5,控制数字前输出的空格!
神奇吧,自己试试printf("%*d",5,10);这个语句
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面请允许我自恋的扮演一下福尔摩斯,找出真相。。。
首先找到,printf的实现代码,GCC里面printf是个壳,也就是说他是利用别人的功能实现的,而这里的”别人“其实就是真正实现数据输出的是下面这个东西
。。。。
_doprnt (const char *format, va_list ap, FILE *stream)
{
const char * ptr = format;
char specifier[128];//格式化输出的那个常量字符串的缓冲区,很关键的一个东东
int total_printed = 0;
while (*ptr != '\0')
{
if (*ptr != '%') /* While we have regular characters, print them. */
PRINT_CHAR(*ptr);
else /* We got a format specifier! */当”扫描"到%的时候,就说明要发生格式化输出了,并且%之后的那个格式说明符就是该数据的读取格式
{
char * sptr = specifier;//指针sptr指向那个缓冲区
int wide_width = 0, short_width = 0;
*sptr++ = *ptr++; /* Copy the % and move forward. */把%保存到格式化输出的那个缓冲区
while (strchr ("-+ #0", *ptr)) /* Move past flags. */读者可以无视这个,和本主题无关
*sptr++ = *ptr++;
if (*ptr == '*')关键的到了!如果那个printf里面那个常量字符串里%后面跟了个*就执行 COPY_VA_INT;这里是个宏定义,我们来看看宏定义是什么
COPY_VA_INT;
------------------------------------------------------------------------------------------------------------------------------------
#define COPY_VA_INT
do { \
const int value = abs (va_arg (ap, int)); \ 取变长参数列表里那个对应的那个参数,此处是5,然后赋值给变量value
char buf[32]; \ 一个新的缓冲区
ptr++; /* Go past the asterisk. */ \ 指向printf常量字符串的下一个位置,这个和主题关系不大,和谐掉
*sptr = '\0'; /* NULL terminate sptr. */ \ 把指向specifier 缓冲区当前位置的指针指向一个空字符
sprintf(buf, "%d", value); \把value的值写到buf缓冲区里面
strcat(sptr, buf); \把buf缓冲区的内容“衔接”到sptr的后面!事情就发生变化了,格式化输出的格式说明符%之后就变成 %5d!!!!所以会有空格输出
while (*sptr) sptr++; \
} while (0)
------------------------------------------------------------------------------------------------------------------------------------
这里sptr是指向specifier缓冲区的,真正按格式化打印数据是按照specifier缓冲区里的字符串格式来打印的,所以如果你没看懂,可以简单的理解成*被替换成printf("%*d",number,var);中的number,然后按照printf("%number d"10);来格式化输出数据