资源描述:
《printf函数实现》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、intprintf(constchar*fmt,...) { inti; charbuf[256]; va_listarg=(va_list)((char*)(&fmt)+4); i=vsprintf(buf,fmt,arg); write(buf,i); returni; } 代码位置:D:/~/funny/kernel/printf.c 在形参列表里有这么一个token:... 这个是可变形参的一种写法。 当传递参数的个数不确定时,就可以用这种方式来表示。 很显然,我们需要一
2、种方法,来让函数体可以知道具体调用时参数的个数。 先来看printf函数的内容: 这句: va_listarg=(va_list)((char*)(&fmt)+4); va_list的定义: typedefchar*va_list 这说明它是一个字符指针。 其中的:(char*)(&fmt)+4)表示的是...中的第一个参数。 如果不懂,我再慢慢的解释: C语言中,参数压栈的方向是从右往左。 也就是说,当调用printf函数的适合,先是最右边的参数入栈。 fmt是一个指针,这个指
3、针指向第一个const参数(constchar*fmt)中的第一个元素。 fmt也是个变量,它的位置,是在栈上分配的,它也有地址。 对于一个char*类型的变量,它入栈的是指针,而不是这个char*型变量。 换句话说: 你sizeof(p)(p是一个指针,假设p=&i,i为任何类型的变量都可以) 得到的都是一个固定的值。(我的计算机中都是得到的4) 当然,我还要补充的一点是:栈是从高地址向低地址方向增长的。 ok! 现在我想你该明白了:为什么说(char*)(&fmt)+4)表示的是...中的第一个参
4、数的地址。 下面我们来看看下一句: i=vsprintf(buf,fmt,arg); 让我们来看看vsprintf(buf,fmt,arg)是什么函数。 intvsprintf(char*buf,constchar*fmt,va_listargs) { char*p; chartmp[256]; va_listp_next_arg=args; for(p=buf;*fmt;fmt++){ if(*fmt!='%'){ *p++=*fmt; continue; } fmt
5、++; switch(*fmt){ case'x': itoa(tmp,*((int*)p_next_arg)); strcpy(p,tmp); p_next_arg+=4; p+=strlen(tmp); break; case's': break; default: break; } } return(p-buf); } 我们还是先不看看它的具体内容。 想想printf要左什么吧 它接受一个格式化的命令,并把指定的匹配的参数格式化输出。 ok,看看i=vspr
6、intf(buf,fmt,arg); vsprintf返回的是一个长度,我想你已经猜到了:是的,返回的是要打印出来的字符串的长度 其实看看printf中后面的一句:write(buf,i);你也该猜出来了。 write,顾名思义:写操作,把buf中的i个元素的值写到终端。 所以说:vsprintf的作用就是格式化。它接受确定输出格式的格式字符串fmt。用格式字符串对个数变化的参数进行格式化,产生格式化输出。 我代码中的vsprintf只实现了对16进制的格式化。 你只要明白vsprintf的功能是
7、什么,就会很容易弄懂上面的代码。 下面的write(buf,i);的实现就有点复杂了 如果你是os,一个用户程序需要你打印一些数据。很显然:打印的最底层操作肯定和硬件有关。 所以你就必须得对程序的权限进行一些限制: 让我们假设个情景: 一个应用程序对你说:os先生,我需要把存在buf中的i个数据打印出来,可以帮我么? os说:好的,咱俩谁跟谁,没问题啦!把buf给我吧。 然后,os就把buf拿过来。交给自己的小弟(和硬件操作的函数)来完成。 只好通知这个应用程序:兄弟,你的事我办的妥妥
8、当当!(os果然大大的狡猾^_^) 这样应用程序就不会取得一些超级权限,防止它做一些违法的事。(安全啊安全) 让我们追踪下write吧: write: moveax,_NR_write movebx,[esp+4] movecx,[esp+8] intINT_VECTOR_SYS_CALL 位置:d:~/kernel