当前位置:网站首页>自己实现printf函数
自己实现printf函数
2020-11-09 15:25:00 【shzwork】
origin:https://www.e-learn.cn/content/qita/716071
首先我们先来了解一下基础知识。
printf格式字符如下所示,
格式字符 |
说明 |
d |
以带符号的十进制形式输出整数(整数不输出符号) |
u |
以无符号十进制形式输出整数 |
x |
以十六进制无符号形式输出整数(不输出前导符0x), 用x则输出十六进制数的a~f时以小写形式输出 |
c |
以字符形式输出,只输出一个字符 |
s |
输出字符串 |
在C语言中,不仅参数的类型可变,而且参数的个数也是可变的.也就是说,在形参表中可以不明确指定传递参数的个数和类型,以上所说的printf函数就是如此.这种函数称之为变参函数。可变长参数函数的参数数目和类型虽然是可变,但其设计原理与固定参数函数的设计原理是一致的,我们有办法告诉变参函数没有指定的参数的个数和类型。
printf的声明如下:
int printf(const char *format, ...);
format:固定参数
... :可变参数(变参)
在C语言中,变参函数的声明是放在atdarg.h标准库中的,当然可以直接包含进来使用它,但我们这里自己定义它(参照头文件的宏定义)。
typedef char * va_list;
/* 当sizeof(n)=1/2/4时,_INTSIZEOF(n)=4 */
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
//#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
//#define va_arg(ap,t) (ap = ap + _INTSIZEOF(t), *(t *)(ap - _INTSIZEOF(t)))
/* 下面这个话的意思是,先指向下一个变量的地址,然后再(减)回来,最后取它原来地址里面的值 */
#define va_arg(ap,t) (*(t *)(ap = ap + _INTSIZEOF(t), ap - _INTSIZEOF(t)))
/*指针用完后指向0地址,防止野指针的出现*/
#define va_end(ap) ( ap = (va_list)0 )
这里需要注意一下#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) -1) & ~(sizeof(int) - 1) ),可能不是很好理解,下面补充一个知识点:由于在x86(32位机器)平台下,GCC编译器默认按4字节对齐,所以当sizeof(n)=1/2/4时,_INTSIZEOF(n)=4这句话的意思是当变量类型是char,unsigned int,int,那么不足4字节的都按照4字节补齐。
下面给出My_printf.c
#include "my_printf.h"
//==================================================================================================
typedef char * va_list;
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
//#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_arg(ap,t) ( *(t *)( ap=ap + _INTSIZEOF(t), ap- _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 ) //这里就不解释了,不难理解
//==================================================================================================
unsigned char hex_tab[]={'0','1','2','3','4','5','6','7',\
'8','9','a','b','c','d','e','f'}; //输出各种进制下的字符
static int outc(int c)
{
__out_putchar(c); //这里的_out_putchar其实就是putchar,在.h中定义
return 0;
}
static int outs (const char *s) //输出字符串
{
while (*s != '\0')
__out_putchar(*s++);
return 0;
}
static int out_num(long n, int base,char lead,int maxwidth)
{
unsigned long m=0;
char buf[MAX_NUMBER_BYTES], *s = buf + sizeof(buf); // sizeof算结束符'\0' ,strlen不算
int count=0,i=0; //注意这里s指向buf的末端,至于为什么继续往下看
*--s = '\0'; //先--,在赋值结束符,因为sizeof算结束符在内的长度
if (n < 0){
m = -n; //如果是输出的是负数就取反
}
else{
m = n;
}
do{
*--s = hex_tab[m%base];
count++;
}while ((m /= base) != 0); //将要打印的数字从个位开始一位一位存储在数组buf中,如果上面不是指向buf末端,
if (n < 0)
*--s = '-'; //负数的话加负号
return outs(s);
}
/*reference : int vprintf(const char *format, va_list ap); */
static int my_vprintf(const char *fmt, va_list ap)
{
char lead=' ';
int maxwidth=0;
for(; *fmt != '\0'; fmt++)
{
if (*fmt != '%') { //顺序查找判断,遇到%就推出,否则继续循环输出
outc(*fmt);
continue;
}
fmt++;
if(*fmt == '0'){ //遇到‘0’说明前导码是0
lead = '0';
fmt++;
}
while(*fmt >= '0' && *fmt <= '9'){ //紧接着的数字是长度,算出指定长度
maxwidth *=10;
maxwidth += (*fmt - '0');
fmt++;
}
switch (*fmt) { //判断格式输出
case 'd': out_num(va_arg(ap, int), 10,lead,maxwidth); break;
case 'o': out_num(va_arg(ap, unsigned int), 8,lead,maxwidth); break;
case 'u': out_num(va_arg(ap, unsigned int), 10,lead,maxwidth); break;
case 'x': out_num(va_arg(ap, unsigned int), 16,lead,maxwidth); break;
case 'c': outc(va_arg(ap, int )); break;
case 's': outs(va_arg(ap, char *)); break;
default:
outc(*fmt);
break;
}
}
return 0;
}
//reference : int printf(const char *format, ...);
int printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
my_vprintf(fmt, ap);
va_end(ap);
return 0;
}
int my_printf_test(void)
{
printf("My_printf test\n\r") ;
printf("test char =%c,%c\n\r", 'A','a') ;
printf("test decimal number =%d\n\r", 123456) ;
printf("test decimal number =%d\n\r", -123456) ;
printf("test hex number =0x%x\n\r", 0x55aa55aa) ;
printf("test string =%s\n\r", "yoyoyo") ;
printf("num=%08d\n\r", 12345);
printf("num=%8d\n\r", 12345);
printf("num=0x%08x\n\r", 0x12345);
printf("num=0x%8x\n\r", 0x12345);
printf("num=0x%02x\n\r", 0x1);
printf("num=0x%2x\n\r", 0x1);
printf("num=%05d\n\r", 0x1);
printf("num=%5d\n\r", 0x1);
return 0;
}
实验结果如下:
版权声明
本文为[shzwork]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/4000302/blog/4710035
边栏推荐
- Method of conversion between JS character and ASCII code
- leetcode算法(1)
- 为什么现在开发一款软件的时间越来越长?
- 中国程序员 VS 日本程序员,满屏的羞羞!
- Why does it take more and more time to develop a software?
- 使用art-Template模板获取天气预报信息
- 毕业一年后接私活赚了10w,还拿了几家大厂offer!
- 什么是网站【新四化】?
- SEO builders, what are the unspeakable hardships?
- 移动安全加固助力 App 实现全面、有效的安全防护
猜你喜欢
高质量的缺陷分析:让自己少写 bug
如何使用Camtasia制作动态动画场景?
程序员过高工资导致加班?应该降低程序员工资?网友:放过其他苦逼的程序员吧
靠“小抄”进字节:拿到这份模板,薪资能翻倍
Android byte beat one side, was hanged by the interviewer! Fortunately, we got the offer from three sides
Simple use of AE (after effects)
CAD tutorial cad2016 installation course
CCF BDCI热门赛题:非结构化商业文本信息中隐私信息识别
I heard that you changed your registered residence overnight. How can you help yourself if you work like ping?
Openyurt in depth interpretation: how to build kubernetes native cloud edge efficient collaborative network?
随机推荐
One year after graduation, I took private jobs to earn 10 W and got offers from several big factories!
Some common types of error exception in Python
Performance comparison of serialization tools such as Jackson, fastjson, kryo, protostuff
The technology masters who ride the wind and waves gather again | Tencent cloud TVP continues to sail
要我说,多线程事务它必须就是个伪命题!
深入分析商淘多用户商城系统如何从搜索着手打造盈利点
Using art template to obtain weather forecast information
What can DNS do besides resolving domain names?
使用基于GAN的过采样技术提高非平衡COVID-19死亡率预测的模型准确性
Decision tree algorithm theory
International top journal radiology published the latest joint results of Huawei cloud, AI assisted detection of cerebral aneurysms
Cad2016 software installation tutorial
SEO建设者,有哪些说不出的苦?
How to use Camtasia to make dynamic animation scene?
Full link stress testing of moral integrity -- the evolution of corpus intelligence
Booker · apachecn programming / back end / big data / AI learning resources 2020.11
Why I strongly recommend custom development of small programs, these benefits you need to understand
Flink的安装和测试
To me, multithreading transaction must be a pseudo proposition!
cad教程 cad2016安装教程