printf函数,一个精简版的实现(putchar)

◇◆丶佛笑我妖孽 提交于 2020-11-11 11:49:27

今天学到了两个技能,其一为使用递归将整数以字符串的形式打印,其二为va_list实现变长参函数。马上综合这两个小技术,实现了一个精简版的printf函数。之所以为精简版,是因为支持功能有限,同时依赖于putchar函数。

  1. 将整数以字符串形式打印 由于整数的长度一般只有11位左右,使用递归来打印很适合。于是设计了一个__number_v2函数,专门负责将整数以字符串形式打印。 这里注意,对于浮点型来说,可以先打印整数部分,然后打印小数点,接着将小数部分乘以1e6(这里限定了保留多少位有效数字)这样就又转化为整数了,继续以__number_v2函数打印。

  2. 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_v2putchar进行封装,是为了统计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 %.
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!