从零实现一个操作系统-day7

我的博客startcraft

字符串函数

因为在内核中,大部分的c标准库函数无法使用,字符串操作的函数又比较常用,所有自己实现一些

include/string.h

#ifndef INCLUDE_STRING_H_
#define INCLUDE_STRING_H_

#include "types.h"

void memcpy(uint8_t *dest, const uint8_t *src, uint32_t len);

void memset(void *dest, uint8_t val, uint32_t len);

void bzero(void *dest, uint32_t len);

int strcmp(const char *str1, const char *str2);

char *strcpy(char *dest, const char *src);

char *strcat(char *dest, const char *src);

int strlen(const char *src);

#endif // INCLUDE_STRING_H_

libs/string.c

#include "string.h" 
void memcpy(uint8_t *dest, const uint8_t *src, uint32_t len)
{
    int i;
    for(i=0;i<len;i++)
    {
        dest[i]=src[i];
        src++;
    }
}

void memset(void *dest, uint8_t val, uint32_t len)
{
    int i;
    char * temp=dest;
    for(i=0;i<len;i++)
        temp[i]=val;
}

void bzero(void *dest, uint32_t len)
{
    memset(dest,0,len);
}

int strcmp(const char *str1, const char *str2)
{
    while(1)
    {
        if(*str1<*str2)
            return -1;
        else if(*str1>*str2)
            return 1;
        if(*str1=='\0')
            return 0;
        str1++;
        str2++;
    }
}

char *strcpy(char *dest, const char *src)
{
    while(*src)
    {
        *dest=*src;
        dest++;
        src++;
    }
    *dest='\0';
    return dest;
}

char *strcat(char *dest, const char *src)
{
    while(*dest)
    {
        dest++;
    }
    while(*src)
    {
        *dest=*src;
        src++;
        dest++;
    }
    *dest='\0';
    return dest;
}

int strlen(const char *src)
{
    int len=0;
    while(*src)
    {
        len++;
        src++;
    }
    return len;
}

屏幕输出函数

现在我们来尝试一下实现printf函数
首先是函数声明

include/debug.h (部分)

#include "console.h"
#include "vargs.h"

// 内核的打印函数
void printk(const char *format, ...);

// 内核的打印函数带颜色
void printk_color(real_color_t back, real_color_t fore, const char *format, ...);

参数表的三个点代表的就是任意个数的实参,然后就是如何在没有形参名的情况下获取到实参
注意到上面的代码包含了另一个头文件,内容如下

includ/vargs.h

#ifndef INCLUDE_VARGS_H_
#define INCLUDE_VARGS_H_

typedef __builtin_va_list va_list;

#define va_start(ap, last) (__builtin_va_start(ap, last))
#define va_arg(ap, type) (__builtin_va_arg(ap, type))
#define va_end(ap)

#endif // INCLUDE_VARGS_H_

这个里面定义的一些宏是用于取得printk函数调用时的所有参数 ,__builtin_va_list这些是gcc内部实现的
当然也可以自己实现,一般定义为宏,如

#define va_list char*
#define __va_rounded_size(TYPE) (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
#define va_start(AP, LASTARG) (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#define va_arg(AP, TYPE) (AP += __va_rounded_size (TYPE),*((TYPE *)  \
		(AP - __va_rounded_size (TYPE))))
#define va_end(ap)      ( ap = (va_list)0 ) 

来分析一下这些宏都干了什么,

  • va_list是一个char*指针
  • __va_rounded_size(TYPE)是字节对齐,在x86的机器上低于4字节会按照四字节对齐,大于4小于8会按照8字节对齐
  • va_start(AP, LASTARG) LASTARG是函数的最后一个固定参数,那么这个宏就是让AP指向可变参数的第一个参数
  • va_arg (AP,TYPE) 的作用就是在已知参数类型的情况下获取当前参数,然后让AP指向下一个参数
  • va_end(ap) 就是最后让ap指向0,结束
    这些在gcc内部都实现了,就不用我们自己管了
    当然这些成立的条件就是参数在内存中是顺序存储的,事实也就是这样,参数会被按顺序压入栈中
    弄明白这些就可以开始写printk函数了
    今天就先到这,明天再来写printk函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值