自己动手写printf

有这样一个简单的问题:求从1加到100的和S(S= 1+2+3+...+99+100),并打印出S。这道题应该是我们刚刚开始学编程语言时老师让我们做的题目吧一个for或者while循环S就搞定了,接下来就是输出S ,我相信对于当时的你百分之百会用printf(),即使现在遇到类似的问题,在大多情况下你也会用printf的。你有没有想过,我们为什么就要用它呢?printf函数是怎样写的?你是否仔细的想过:为什么我们想让它输出什么它就能输出什么?现在,我们就带着这些问题一起来探讨一下神奇的printf().

假如我想打印一串字符:Hello World!(记得当时我们C语言教材上第一个例子就是它),你的解决办法是什么?我想最简单最直接的办法就是用printf,如{printf("Hello World!");} 。在举个例子,还是求S= 1+2+3+...+99+100并打印出结果,求的和S=5050,如何打印呢?还是用printf。怎么,printf想打印什么数据类型就打印什么数据类型吗?这时,我们一起查一下手册,我们发现printf的输出功能是如此的强大,各种数据类型它是通吃啊!不仅如此,它还能将多个数据类型的组合一同打印出来。这时,我们的问题就来了,它到底是怎样实现数据类型的识别的?特别是printf函数是怎样实现自由变参的?

对于printf如何实现数据类型的识别,这点很容易:当遇到%的时候就对下一个字符做判断,如果是d,那么输出的应该是int型的数;如果是s,那么输出的应该是字符串;如果是f,那么输出的应该是float型的数等等。其实这些都很容易理解并且实现。在我看来,printf的精髓所在就是它变参的实现。下面就着重说一下变参的实现过程。

其实printf的变参看起来挺奇妙,不过当你实际了解它的实现之后,或许你可能会想:也就那样了!或许你可能会感叹:原来如此!不管怎样,我们先一睹它的真容吧!

可变参数主要由stdarg.h中定义的四个宏实现,具体步骤如下:

step 1:在调用参数表之前,应该定义一个 va_list 类型的变量,以供后用(下面假设这个 va_list 类型变量被定义为ap)

step 2:然后对该ap进行初始化,让它指向可变参数表里面的第一个参数,这是通过 va_start 来实现的,第一个参数是 ap 本身,第二个参数是在变参表前面紧挨着的一个变量

step 3:然后是获取参数,调用 va_arg,它的第一个参数是 ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置

step 4:获取所有的参数之后,我们有必要将这个 ap 指针关掉,以免发生危险,方法是调用 va_end,他是输入的参数 ap 置为 NULL,应该养成获取完参数表之后关闭指针的习惯

看到了吧,实现的过程就是这么简单,你可以自己亲自动手写一个试试。

上面就是实现printf的主要部分,有关某些细节的东西我自己也想不了那么多。我对printf的理解也就是这么个样子了。

用了这么长时间的printf了,也曾经想过为什么,但就是没有自己实现它。现在趁着国庆的假期,在家里除了吃喝,剩下的就是大把的时间了。于是乎,我便下决心珍惜这短暂的光阴,自己动手写printf函数。我很享受写它的过程,毕竟对它很了解了。下面就是我自己完成的printf------>printf_FC.

代码如下:

头文件

#include <stdio.h> #include <stdarg.h>


/***The printf_FC equals to printf which incuds in <stdio.h>***/

int printf_FC(const char *format, ...) { va_list unnamed_p; char *p, *sval; unsigned int value_i; va_start( unnamed_p, format); for ( p=(char *)format; *p; p++ ) { if ( *p != '%' ) { putchar( *p ); continue; } switch ( *++p ) { case 'd': value_i = va_arg( unnamed_p, unsigned int ); output_convert( value_i, 10 ); break; case 's': for (sval = va_arg(unnamed_p, char*); *sval; sval++) putchar( *sval ); break; case 'x': value_i = va_arg( unnamed_p, unsigned int ); output_convert( value_i, 16 ); break; default: putchar( *p ); break; } } va_end( unnamed_p ); return 0; }


/***The function is to convert an integer to int or hex***/

void output_convert( unsigned int num, const int base ) { const char *digit = "0123456789ABCDEF"; unsigned int buf[32]; int i = 0; char ch; if (base == 10) { do { buf[i] = num % 10; num = num / 10; i++; } while ( num > 0 ); } if (base == 16) { do { buf[i] = num % 16; num = num / 16; i++; } while ( num > 0 ); } while ( --i >= 0 ) { ch = digit[buf[i]]; putchar( ch ); } }


/*** main() and test function ***/

int printf_test(void) { char buf[16] = "abcd"; int counter = 0; printf_FC("hello, test printf! \n"); printf_FC("test str: %s \n", buf); for(; counter < 5 ; counter++) { printf_FC("test int: %d \n", counter); printf_FC("test hex: 0x%x \n", counter); printf_FC("\n"); } return 0; } int main() { printf_test(); return 0; }


Testing Result As Follows:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值