打印

C解析之十二C语言prinft函数的秘密

[复制链接]
1604|8
手机看帖
扫描二维码
随时随地手机跟帖
沙发
elecintop|  楼主 | 2014-4-29 10:19 | 只看该作者
从C语言的第一个程序Hello World开始,到目前所写的几乎所有C程序都有它的出场,它便是: 标准化输出函数printf。printf超高的出场率让人对它习以为常,似乎printf函数的独特性也不被人所注意。

使用特权

评论回复
板凳
elecintop|  楼主 | 2014-4-29 10:20 | 只看该作者
1.变长参数:不可思议
你可能没有注意:printf函数的参数是变长参数。
printf("Hello World !");
ptintf("%d",number);
printf("Two number:%d %d",number1,number2);
首先,试图从函数相关的知识解析这个问题,...  ,最后只能得出一个结论:不可思议。

使用特权

评论回复
地板
elecintop|  楼主 | 2014-4-29 10:21 | 只看该作者
2.printf常见使用格式:
printf(char *format,arg1,arg2 ...);
其中format称为格式化字符串:包含普通字符和转换字符。输出时,普通字符原封不动地复制到输出流中,转换字符则用于控制参数的输出方式。
arg1,arg2  ...是参数列表。
如:printf("Hello World !");
格式化字符串仅包含普通字符串"Hello World !",则"Hello World !"按原样输出。
再如: printf("Two number:%d %d",number1,number2);
格式化字符串包含普通字符串"Two number:"和转换字符串"%d %d","Two number:"原样输出,转换字符串则用于控制number1,number2的输出。

使用特权

评论回复
5
elecintop|  楼主 | 2014-4-29 10:22 | 只看该作者
3.prinft定义格式:
int printf(char *format, ... )
此处的省略号...表示参数的数量与类型可变。
关键:如何处理...代表的参数表,它甚至连名字都没有。答案在标准头文件<stdarg.h>中的一组宏定义,这组宏定义提供了遍历参数表的方法。va_list类型用于声明一个变量,该变量将依次引用参数表的各个参数。va_start将va_list变量指向第一个无名参数。va_arg返回参数表中的一个参数,并将va_list变量指向下一个无名参数。va_arg根据一个数据类型名决定返回参数的类型与指针移到的步长。va_end用于最后做一些清理工作。

使用特权

评论回复
6
elecintop|  楼主 | 2014-4-29 10:23 | 只看该作者
4.编写自己的printf函数:
#include<stdarg.h> //宏定义在该头文件内
#include<stdio.h> //需要putchar,printf支持(某些类型转化),
void Myprintf(char * format,...)
{
va_list ap; //定义一个va_list变量,用来遍历无名参数表
char *p; //p用于变量 格式化字符串format
char *sval; //存储提取的字符串参数
int ival; //存储提取的整型参数
double dval; //存储提取的浮点型参数
va_start(ap,format); //va_start以最后一个有名参数format为参数,将ap指向第一个无名参数
for(p=format;*p;p++)
{
if(*p!='%')
{
putchar(*p);
continue;
}
switch(*++p)
{
case 'd':
ival=va_arg(ap,int); //va_arg根据int,返回一个int参数,并决定指针偏移的步长(int显然为4)
printf("%d",ival);
break;
case 'f':
dval=va_arg(ap,double); //va_arg返回一个double,指针偏移8
printf("%f",dval);
break;
case 's':
for(sval=va_arg(ap,char *);*sval;sval++)
putchar(*sval);
break;
default:
putchar(*p);
break;
}
}
va_end(ap); //结束时清理工作
}
int main(){
int n=10;
double m=8.8;
char s[10]="hello";
Myprintf("This is test !\n");
Myprintf("This int : %d \n",n);
Myprintf("This double:%f\n",m);
Myprintf("This string:%s\n",s);
return 0;
}

使用特权

评论回复
7
elecintop|  楼主 | 2014-4-29 10:23 | 只看该作者
实现一个Myprintf很容易吧,出于复杂度与突出重点的考虑,Myprintf没有实现自己的int,double转换,它的int,double的转换实际上借用了printf的转换,所以需要包含stdio.h,但不要纠结于这些无关紧要的细节。通过Myprintf,printf如何使用变长的参数表,printf的工作机制便清晰地浮出水面。

使用特权

评论回复
8
一毛钱0| | 2014-5-8 12:09 | 只看该作者

使用特权

评论回复
9
xy123151| | 2014-5-10 17:10 | 只看该作者
长姿势了,平常用着printf都没想过是什么原理

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

176

主题

1329

帖子

3

粉丝