C语言从最基础实现printf
众所周知,printf是c语言中非常重要也非常常用的函数了,那下面我们就尝试自己实现一下printf
printf最常处理的一些数据类型
符号 | 意义 |
---|---|
%d | 十进制有符号整数 |
%u | 十进制无符号整数 |
%f | 浮点数 |
%s | 字符串 |
%c | 单个字符 |
%p | 指针的地址 |
%e | 指数形式的浮点数 |
%x, %X | 无符号以十六进制表示的整数 |
%o | 无符号以八进制表示的整数 |
%p | 输出地址符 |
PS: %#o、%#x、%#X -> 在结果前增加前缀 0、0x、0X;
printf原函数
int printf( const char *format, ... );
format – 是格式控制字符串,包含了两种类型的对象:
1、普通字符和转换说明。在输出的时候,普通字符将直接输出,例如:
printf("Hello world");//输出直接为:Hello world
2、转换说明并不直接输出而是用于控制 printf 中参数的转换和打印。
每个转换说明都由一个百分号字符(%)开始,以转换说明结束,从而说明输出数据的类型、宽度、精度等,例如:
printf("%d,%c,%s\n",1,a,"hello world");
//结果为
1,a,hello world
输入
int my_printf(char *format, ...)
{
va_list arg;//(定义一个变参变量,相当于一个char *)
va_start(arg, format);//fotmat是固定参数,经过 va_start(arg,format)后,移动指针arg到第一个变参变量
char *begin = format;//之后我们将主要使用begin处理输入的数据
}
那么根据上面我们列出的表格,输入形式大概分为三大种
- %…
- %#…
- 文字
int my_printf(char *format, ...)
{
va_list arg;
va_start(arg, format);
char *begin = format;
while (*begin != '\0') {
if ((*begin == '%') && (judge(begin) == 1)) {
begin++;
situ_gene(begin,arg);
} else {
if ((*(begin - 1) == '#' || *(begin - 1) == '+')
&& *(begin + 1) != '%')
*begin++;
my_putchar(*begin);
}
*begin++;
}
va_end(arg);
return (0);
}
输出
接下来我们可以使用if或者switch对接收到的不同的命令作出不同的处理
但我个人更加倾向于使用switch,代码简洁明了
switch (*begin) {//这里的begin就是将指针移到%或者%#后的字符,我们只需要判断他是c(%c)还是d(%d)还是s(%d)等等
case 'c':
my_putchar(va_arg(arg, int));
break;
case 'd': case 'i':
//va_arg:arg指向变参数列表中的下一个参数,返回arg指向的参数值,是一个类型为int的表达式。
my_put_nbr(va_arg(arg, int));
break;
case 's':
my_putstr(va_arg(arg, char*));//va_arg返回char*表达式
break;
case 'f':
get_float(va_arg(arg, double));
break;
default:
normal_situ(begin,arg);
break;
//我个人有个格式“洁癖”。。就是一段function我不会写超过20行。。所以default是连接着另一个switch。
}
完整代码链接点这里,麻烦要下载的大家,顺手给我点一个star
如果有讲的不清楚的地方,大家可以在下方评论留言,完整代码中附带所有我自己写的基础的函数,例如:
putchar
putnbr
putstr
strlen
pow
还有十进制转二进制,转十六进制等等
希望文章能帮到大家