今天学到了两个技能,其一为使用递归将整数以字符串的形式打印,其二为va_list
实现变长参函数。马上综合这两个小技术,实现了一个精简版的printf
函数。之所以为精简版,是因为支持功能有限,同时依赖于putchar
函数。
-
将整数以字符串形式打印 由于整数的长度一般只有
11
位左右,使用递归来打印很适合。于是设计了一个__number_v2
函数,专门负责将整数以字符串形式打印。 这里注意,对于浮点型来说,可以先打印整数部分,然后打印小数点,接着将小数部分乘以1e6
(这里限定了保留多少位有效数字)这样就又转化为整数了,继续以__number_v2
函数打印。 -
var_arg实现变参函数 以下是在
Windows 10
中的Visual Studio 2015
上编译通过。基本框架就是首先声明一个va_list
,接着使用一对__crt_va_start
、__crt_va_end
来设定范围,使用__crt_va_arg
来解析变参。这时候要注意,- 其一在
__crt_va_start
时,需要一个初始化工作。 - 其二就是使用
__crt_va_arg
提取参数时需要指定参数类型。
- 其一在
这里使用__char_v2
对putchar
进行封装,是为了统计printfv2
所打印的总长度,也就是为获取ans
的值。
static int __char_v2(char c, int* count) { putchar(c); return ++(*count); } |
static void __number_v2(unsigned int number, int* count) { unsigned int quotient = number / 10; if (quotient != 0) { __number_v2(quotient, count); } __char_v2(number % 10 + '0', count); } |
int (const char* format, ...) { va_list var_arg; int ans = 0, tmp_int = 0; double tmp_double = 0; char* tmp_charptr = ''; char c = ''; if (!format) return ans; __crt_va_start(var_arg, format); while ((c = *format) != '') { if (c == '%') { switch (*(++format)) { case 'f': tmp_double = __crt_va_arg(var_arg, double); if (tmp_double < 0) { __char_v2('-', &ans), tmp_double = -tmp_double; } __number_v2((int)tmp_double, &ans); __char_v2('.', &ans); __number_v2((int)((tmp_double - (int)tmp_double)*1e6), &ans); break; case 'd': tmp_int = __crt_va_arg(var_arg, int); if (tmp_int < 0) { __char_v2('-', &ans), tmp_int = -tmp_int; } __number_v2(tmp_int, &ans); break; case 's': tmp_charptr = __crt_va_arg(var_arg, char*); while (*tmp_charptr != '') { __char_v2(*(tmp_charptr++), &ans); } break; case 'c': __char_v2(__crt_va_arg(var_arg, char), &ans); break; default: __char_v2(c, &ans), __char_v2(*format, &ans); break; } ++format; } else { __char_v2(*(format++), &ans); } } __crt_va_end(var_arg); return ans; } |
int () { int ans = 0; ans = printfv2("My name is %s, I am %d years old, %fkg in the title, I like the letter %c.n", "DUJUN QING", 18, 56.789, 'X'); printfv2("Length is %d.n", ans); printfv2("There is a negative number (%f) here, and a percent sign %.n", -12.3); return 0; } |
输出内容,
My name is DUJUN QING, I am 18 years old, 56.789000kg in the title, I like the letter X. Length is 89. There is a negative number (-12.300000) here, and a percent sign %. |
来源:oschina
链接:https://my.oschina.net/u/4000302/blog/4712318