操作系统在启动之初,或检测到内部错误时,就需要向控制台输出有关信息。可以想象,这在操作系统中是潜在的常用过程。无论是UNIX,还是Linux,作为操作系统的内核部分,都尤其注意了程序的执行效率。我们所选的过程,它们的魅力,都可以用“清丽”之词言之;清丽之意,乃介乎天生丽质,韵味内涵皆清晰可观。我们细致的来看它们魅力与异同。
Ⅰ.UNIX部分(printf)
在UNIX中,是文件prf.c里的过程printf来完成这项工作的。它调用了其他一些过程,程序如下:
/*UNIX 6 — prf.c
*我们所选的过程为printf和printn。可对应于莱昂氏原2340至2378行的程序部分。
*/
001 printf(fmt,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc)
002 char fmt[];
003 {
004 register char *s;
005 register *adx, c;
006
007 adx = &x1;
008 loop:
009 while((c = *fmt++) != ‘%’) {
010 if(c == ‘ ’)
011 return;
012 putchar(c);
013 }
014 c = *fmt++;
015 if(c == ‘d’ || c == ‘l’ || c == ‘o’)
016 printn(*adx,c==’o’: 10);
017 if(c == ‘s’) {
018 s = *adx;
019 while(c = *s++)
020 putchar(c);
021 }
022 adx++;
023 goto loop;
024 }
025 /*————————–*/
026
027 printn(n, b)
028 {
029 register a;
030
031 if(a = ldiv(n, b))
032 printn(a, b);
033 putchar(lrem(n, b) + ‘0’);
034 }
035 /*————————–*/
036
037 /*putchar(c);*/
038
对程序做简单说明。首先您注意到,这里c语言是旧时的风格,由printf的参数fmt可看出。还有就是,过程putchar涉及硬件相关的知识,同样,过程ldiv和lrem是汇编语言的过程,我们为简略起见,不再分析相关代码,而只提供如下提示:
对于printn,假设 n = A*b+B,则其中
lA=ldiv(n,b),而且
lB=lrem(n,b),0
过程printf是一种简单而直接的方法,可以方便的向系统控制台终端发送消息。并无缓存,也没有消息的优先级,后面可以看到这和我们所选的Linux的那个过程是不一样的。而且,printf和putchar都在核心态下运行,类似但不同于由C程序调用库函数“printf”和“putchar”,后者其实是在用户态下运行的。
现在您可以回过头去,试着品味一下这段代码。
我们先看过程printf。
007007 寄存器变量adx记录了第一个参数x1的地址,注意x1占用的是栈单元,编译时不能对此表达
式求值。从008到023,则是一个大循环,关乎我们的全部工作。
009 009至013一个while循环,消息字符串在fmt内,而这里,边输出消息,边检测可有
“%d”、“%l”、“%o”或“%s”出现,分别表明后面的参数里有十进制数、八进制数或字
符串内容需要输出。如果遇到结束符,则返回。
014014可以和009里相同的部分对照看。C语言的简练,竟可至此。当在009里,若寄存器变量c取出
字符‘%’时,其后fmt会后移一位,转到014执行。而这里是先取fmt内容,然后后移,则
c可为‘d’、‘l’、‘o’或‘s’了。若fmt中无‘%’出现,则整个字符串被送出后过程
就立刻返回,没有执行014及其后程序的可能,也就没有fmt超界的险情。这是逻辑力量的魅
力。
015与016调用了递归过程printn。后面详细叙述。
017 017至021处理字符串s。整个过程比较清晰,看上去也极易明白。
022022adx后移一位。最初adx存储的是谁的地址个参数x1的。后移一位指向哪里细
一看,其它参数如x2、x3等皆未在程序中用到。您是否有些糊涂了p>
C语言程序设计在过程调用和过程说明时,两者之间的参数不进行匹配检查。参数皆按逆序放到栈上,如图:
文章知识点与官方知识档案匹配,可进一步学习相关知识CS入门技能树Linux入门初识Linux25345 人正在系统学习中 相关资源:向氏打字通源码,VB6打字软件仿金山打字通–其它代码类资源–CSDN文库
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!