3. 库函数的实现

声明: 此系列文章尚未完成,请勿转载,谢谢合作

梗概
这一节新增的文件有:
stdarg.h       用来处理可变参数
ctype.h        判断变量一些属性。比如一个字符是不是大写,是不是数字
string.h string.c      常用的关于字符串的操作
vsprintf.h vsprintf.c       该节的主要文件用来实现格式化输出
改变的文件有:
test.c         主要用来测试 printk函数


正文

大家上程序设计课程写的第一个程序应该是hello world吧,它仅仅是用printf函数打印一条问候语句,是的,非常简单。但是想在内核中用printf可就没那么容易了,因为内核程序根本就不能使用C库函数,但是printf函数却又非常重要。怎么办?大家应该还记得上一节写的vga驱动,用它直接打印不就得了。醒醒吧,printf可没那么简单,它不仅要能打印字符串,还要控制格式,就像这样: printf("Tinux is %d years old.", 2)。cons_write函数可不会把%d替换成数字2。看来还是要自己动手,才能丰衣足食了。

本节目标就是实现printf函数,不过我给它取了另一个名字叫printk,以表明它是用在内核当中的printf函数。另外还会有些附带的函数产品,像strcpy,memcpy等字符串操作函数,sprintf,vsprintf等底层打印函数。printk函数就是靠vsprintf实现的。

可变 参数的头文件 stdarg.h
请拿出你的C语言参考书,看一下printf函数的声明: int printf(const char *format, ...);
是的,这就是传说中的变长参数。我在这里只提供变长参数的大概知识,详情请看 变长参数的实现。变长参数涉及一个自定义的数据类型va_list,和三个宏定义va_start, va_arg, va_end。他们都定义在头文件stdarg.h中,我是直接通过gcc内置宏定义的,与链接给出的文章不同,因为那篇文章是为了讲解变长参数,真正实现时用gcc内置宏就可以了,相当于gcc内置宏为我们做好了定义,这样正确率更高,要知道调试OS Kernel可是相当烦。
ContractedBlock.gif ExpandedBlockStart.gif stdarg.h
 1 #ifndef __STDARG_H__
 2 #define __STDARG_H__
 3 
 4 #define va_list            __builtin_va_list
 5 #define va_start(ap, last) __builtin_va_start (ap, last)
 6 #define va_arg(ap, type)   __builtin_va_arg   (ap, type)
 7 #define va_end(ap)         __builtin_va_end   (ap)
 8 
 9 #endif
10 

C类型头文件 ctype.h
里面都是些常用宏,比如 islower(c)判断c是不是小写字母,isdigit(c)判断c是不是十进制数码,isxdigit(c)判断c是不是十六进制数码
isspace(c)判断c是不是空白字符
ContractedBlock.gif ExpandedBlockStart.gif ctype.h
 1 #ifndef __CTYPE_H__
 2 #define __CTYPE_H__
 3 
 4 #define islower(c) (((c) >= 'a') && ((c) <= 'z'))
 5 #define isupper(c) (((c) >= 'A') && ((c) <= 'Z'))
 6 #define isalpha(c) (islower (c) || isupper (c))
 7 #define isdigit(c) (((c) >= '0') && ((c) <= '9'))
 8 #define isalnum(c) (isalpha (c) || isdigit (c))
 9 #define ispunct(c)                          \
10     ((((c) >= 0x21&& ((c) <= 0x2f)) ||    \
11      (((c) >= 0x3a&& ((c) <= 0x40)) ||    \
12      (((c) >= 0x5b&& ((c) <= 0x60)) ||    \
13      (((c) >= 0x7b&& ((c) <= 0x7e)))
14 #define isgraph(c) (((c) >= 0x21) && ((c) <= 0x7e))
15 #define isspace(c) ((((c) >= 0x09) && ((c) <= 0x0d)) || ((c) == ' '))
16 #define isprint(c) (((c) >= 0x20) && ((c) <= 0x7e))
17 #define iscntrl(c) (((c) <= 0x1f) || ((c) == 0x7f))
18 #define isxdigit(c)                                     \
19     (isdigit (c) || (((c) >= 'a'&& ((c) <= 'f')) ||   \
20     (((c) >= 'A'&& ((c) <= 'F')))
21 
22 #define tolower(c) (isupper (c) ? (c)+'a'-'A' : (c))
23 #define toupper(c) (islower (c) ? (c)+'A'-'a' : (c))
24 
25 #endif
26 

字符串处理 string.h string.c
关于 memcpy函数和mememove函数的区别请自行Google
ContractedBlock.gif ExpandedBlockStart.gif string.h
 1 #ifndef __STRING_H__
 2 #define __STRING_H__
 3 
 4 #include "types.h"
 5 
 6 void *memcpy (void *dest, const void *src, size_t n);
 7 void *memmove (void *dest, const void *src, size_t n);
 8 char *strcpy (char *dest, const char *src);
 9 char *strncpy (char *dest, const char *src, size_t n);
10 int strcmp (const char *s1, const char *s2);
11 int strncmp (const char *s1, const char *s2, size_t n);
12 int strlen (const char *s);
13 
14 #endif

ContractedBlock.gif ExpandedBlockStart.gif string.c
 1 #include "types.h"
 2 #include "string.h"
 3 
 4 void *memcpy (void *dest, const void *src, size_t n) {
 5     int i;
 6     for (i = 0; i < (int)n; i++*(char *)(dest + i) = *(char *)(src + i);
 7     return dest;
 8 }
 9 
10 void *memmove (void *dest, const void *src, size_t n) {
11     int i;
12     if (src > dest) 
13         for (i = 0; i < (int)n; i++)
14             *(char *)(dest + i) = *(char *)(src + i);
15     if (src < dest)
16         for (i = (int)(n - 1); i >= 0; i--)
17             *(char *)(dest + i) = *(char *)(src + i);
18     return dest;
19 }
20 
21 char *strcpy (char *dest, const char *src) {
22     int i = 0;
23     do { dest[i] = src[i]; } while (src[i++!= 0);
24     return dest;
25 }
26 
27 char *strncpy (char *dest, const char *src, size_t n) {
28     int i = 0;
29     while ((i < (int)n) && (src[i] != 0)) { dest[i] = src[i]; i++; }
30     while (i < (int)n) dest[i++= 0;
31     return dest;
32 }
33 
34 int strcmp (const char *s1, const char *s2) {
35     int i = 0;
36     while ((s1[i] == s2[i]) && (s1[i] != 0)) i++;
37     return s1[i] - s2[i];
38 }
39 
40 int strncmp (const char *s1, const char *s2, size_t n) {
41     int i = 0;
42     while ((i < (int)n) && (s1[i] == s2[i]) && (s1[i] != 0)) i++;
43     return (i == (int)n) ? 0 : s1[i] - s2[i];
44 }
45 
46 int strlen (const char *s) {
47     int i = 0;
48     while (s[i] != 0) i++;
49     return i;
50 }
51 

打印函数 vsprintf.h vsprintf.c
ContractedBlock.gif ExpandedBlockStart.gif vsprintf.h
 1 #ifndef __VSPRINTF_H__
 2 #define __VSPRINTF_H__
 3 
 4 #include "stdarg.h"
 5 
 6 int sprintf(char *str, const char *format, );    // 将输出重定向到缓冲区 str
 7 int vsprintf (char *str, const char *format, va_list ap);    // 这是一个中转函数,真正完成格式化功能
 8 int printk(const char *format, );    // 和 printf一样
 9 
10 #endif

ContractedBlock.gif ExpandedBlockStart.gif vsprintf.c
  1 #include "types.h"
  2 #include "ctype.h"
  3 #include "console.h"
  4 #include "stdarg.h"
  5 #include "string.h"
  6 #include "vsprintf.h"
  7 
  8 /* flags */
  9 #define LEFT    0x01
 10 #define PLUS    0x02
 11 #define SPACE   0x04
 12 #define SPECIAL 0x08
 13 #define ZERO    0x10
 14 #define SIGN    0x20 /* signed if set */
 15 #define SMALL   0x40 /* 'abcdef' if set, 'ABCDEF' otherwise */
 16 
 17 int32_t get_wide (const char **s);
 18 void number_to_string (long num, int32_t base, int32_t flags, int32_t wide, int32_t precision, char **s);
 19 
 20 int sprintf(char *str, const char *format,) {
 21     va_list args;
 22     int32_t res;
 23     va_start (args, format);
 24     res = vsprintf(str, format, args);
 25     va_end (args);
 26     return res;
 27 }
 28 
 29 int32_t vsprintf (char *str, const char *format, va_list ap) {
 30     char c;
 31     char *start = str;
 32     int32_t flags;
 33     int32_t wide;
 34     int32_t precision;
 35     int32_t qualifier;
 36     char *s;
 37     int32_t i, len, base;
 38 
 39     while ((c = *format++!= 0) {
 40         if (c != '%') { *str++ = c; continue; }
 41         if (*format == '%') { *str++ = '%'; format++continue; }
 42 
 43         /* get flags */
 44         flags = 0;
 45         while (1) {
 46             if (*format == '-') { flags |= LEFT;    format++continue; }
 47             if (*format == '+') { flags |= PLUS;    format++continue; }
 48             if (*format == ' ') { flags |= SPACE;   format++continue; }
 49             if (*format == '#') { flags |= SPECIAL; format++continue; }
 50             if (*format == '0') { flags |= ZERO   ; format++continue; }
 51             break;
 52         }
 53 
 54         /* get wide */
 55         wide = -1;
 56         if (isdigit (*format)) wide = get_wide ((const char **)(&format));
 57         else if (*format == '*') { wide = va_arg (ap, int32_t); format++; }
 58 
 59         /* get precision */
 60         precision = -1;
 61         if (*format == '.') {
 62             format++;
 63             if (isdigit (*format))
 64                 precision = get_wide ((const char **)(&format));
 65             else if (*format == '*') {
 66                 precision = va_arg (ap, int32_t);
 67                 format++;
 68             }
 69             else precision = 0;
 70         }
 71 
 72         /* get qualifier */
 73         qualifier = -1;
 74         if ((*format == 'h'|| (*format == 'l')) qualifier = *format++;
 75 
 76         /* get format */
 77         switch (*format++) {
 78             case 'i':
 79             case 'd':
 80                 flags |= SIGN;
 81                 if (precision != -1) flags &= ~ZERO;
 82                 switch (qualifier) {
 83                     case 'h':
 84                         number_to_string ((short) va_arg (ap, int32_t), 10, flags,
 85                             wide, precision, &str);
 86                         break;
 87                     case 'l':
 88                         number_to_string (va_arg (ap, long), 10, flags,
 89                             wide, precision, &str);
 90                         break;
 91                     default:
 92                         number_to_string (va_arg (ap, int32_t), 10, flags,
 93                             wide, precision, &str);
 94                         break;
 95                 }
 96                 break;
 97 
 98             case 'u':
 99                 base = 10;
100                 goto num_to_str_without_sign;
101 
102             case 'o':
103                 base = 8;
104                 goto num_to_str_without_sign;
105 
106             case 'x':
107                 flags |= SMALL;
108             case 'X':
109                 base = 16;
110 
111                 num_to_str_without_sign:
112                 flags &= (~PLUS & ~SPACE);
113                 if (precision != -1) flags &= ~ZERO;
114                 switch (qualifier) {
115                     case 'h':
116                         number_to_string ((unsigned short) va_arg (ap, int32_t), \
117                             base, flags, wide, precision, &str);
118                         break;
119                     case 'l':
120                         number_to_string ((unsigned long) va_arg (ap, long), \
121                             base, flags, wide, precision, &str);
122                         break;
123                     default:
124                         number_to_string((uint32_t)va_arg (ap, int32_t), \
125                          base, flags, wide, precision, &str);
126                         break;
127                 }
128                 break;
129 
130             case 's':
131                 s = va_arg (ap, char *);
132                 len = strlen (s);
133                 if ((precision >= 0&& (len > precision)) len = precision;
134 
135                 /* rigth justified : pad with spaces */
136                 if (!(flags & LEFT)) while (len < wide--*str++ = ' ';
137                 for (i = 0; i < len; i++*str++ = *s++;
138                 /* left justified : pad with spaces */
139                 while (len < wide--*str++ = ' ';
140                 break;
141 
142             case 'c':
143                 /* rigth justified : pad with spaces */
144                 if (!(flags & LEFT)) while (1 < wide--*str++ = ' ';
145                 *str++ = (unsigned char) va_arg (ap, int32_t);
146                 /* left justified : pad with spaces */
147                 while (1 < wide--*str++ = ' ';
148                 break;
149 
150             default:
151                 return -1;
152         }
153     }
154     *str = 0;
155         
156     return (int32_t)(str-start);
157 }
158 
159 int32_t printk(const char *format, )
160 {
161     char buff[1024];
162     char *str = buff;
163     va_list args;
164     int32_t res;
165     va_start (args, format);
166     res = vsprintf (str, format, args);
167     va_end (args);
168     cons_write(buff);
169     return res;
170 }
171 
172 int32_t get_wide (const char **s) {
173     int32_t res = 0;
174     while (isdigit (**s)) res = 10*res + *((*s)++- '0';
175     return res;
176 }
177 
178 #define LONG_STRSIZE_BASE_2 32
179 
180 void number_to_string (long num, int32_t base, int32_t flags, int32_t wide, int32_t precision, char **s) {
181     char sign;  /* sign printed : '+', '-', ' ', or 0 (no sign) */
182     int32_t num_cpy = num;
183     unsigned long ul_num = (unsigned long) num; /* for unsigned format */
184 
185     /* string representation of num (reversed) */
186     char tmp[LONG_STRSIZE_BASE_2];
187     int32_t i = 0/* number of figures in tmp */
188 
189     const char *digits = "0123456789ABCDEF";
190     if (flags & SMALL) digits = "0123456789abcdef";
191 
192     if ((base < 2|| (base > 16)) return;
193 
194     if ((flags & SIGN) && (num < 0)) { sign = '-'; num = -num; }
195     else sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0);
196     if (sign) wide--;
197 
198     if (flags & SPECIAL) {
199         if ((base == 16&& (num != 0)) wide -= 2;  /* '0x' or '0X' */
200         if (base == 8) { wide--; precision--; }     /* '0' */
201     }
202     
203     if (num == 0) tmp[i++= '0';
204     /* signed format */
205     if (flags & SIGN) {
206         while (num != 0) {
207             tmp[i++= digits[num % base];
208             num = num / base;
209         } 
210     }
211     /* unsigned format */
212     else {
213         while (ul_num != 0) {
214             tmp[i++= digits[ul_num % base];
215             ul_num = ul_num / base;
216         } 
217     }
218 
219     if (i > precision) precision = i;
220     wide -= precision;
221 
222     /* wide = number of padding chars */
223     /* precision = number of figures after the sign and the special chars */
224 
225     /* right justified and no zeropad : pad with spaces */
226     if (!(flags & (LEFT + ZERO))) while (wide-- > 0*((*s)++= ' ';
227 
228     if (sign) *((*s)++= sign;
229     if ((flags & SPECIAL) && (num_cpy != 0)) {
230         if (base == 8*((*s)++= '0';
231         if (base == 16) {
232             *((*s)++= '0';
233             if (flags & SMALL) *((*s)++= 'x';
234             else *((*s)++= 'X';
235         }
236     }
237 
238     /* rigth justified and zeropad : pad with 0 */
239     if (!(flags & LEFT)) while (wide-- > 0*((*s)++= '0';
240 
241     /* print num */
242     while (i < precision--*((*s)++= '0';
243     while (i-- > 0*((*s)++= tmp[i];
244 
245     /* left justfied : pad with spaces */
246     while (wide-- > 0*((*s)++= ' ';
247 }
248 

这一节的程序和上节的一样,起基础作用,并没有关系到进程,内存管理等OS核心理论。但是它们的正确与否至关重要,这也是OS研究的繁琐之处,想要一探它的奥秘还必须先做一些杂七杂八的玩意儿。

测试程序 test.c
让该程序做一些算术题目,并格式化输出结果

ContractedBlock.gif ExpandedBlockStart.gif test.c
 1 #include "console.h"
 2 #include "vsprintf.h"
 3 
 4 int test(void)
 5 {
 6     int a = 32;
 7     int b = 68;
 8     cons_clear();
 9     printk("\n\n");
10     printk("                                November 8, 2009\n");
11     printk("Hi,John\n\n"); 
12     printk("Now, I am capable of caculating math expressions,\n");
13     printk("and what's more, showing the results to our friends.\n");
14     printk("Look!\n\n");
15     printk("       %d + %d = %d \n",a, b, a+b);
16     printk("       0x%x + 0x%x = 0x%x \n",a,b,a+b);
17     printk("                                       Your Tinux\n");
18     return 0;
19 }



运行结果如下:
                

PS: 此节的程序几乎全部来自CROCOS, 这是个开源OS项目, 它的新颖之处在于OS开发方式, 先像开发用户程序一样开发OS组件,最后再移到真实的硬件环境中。
    若有兴趣,请访问 http://crocos.sourceforge.net/


Tinux Kernel源码下载 Tinux3.zip

转载于:https://www.cnblogs.com/john-d/archive/2009/11/08/1598416.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值