手写操作系统(二十五)-实现字符串操作函数

代码、内容参考来自于包括《操作系统真象还原》、《一个64位操作系统的设计与实现》以及《ORANGE’S:一个操作系统的实现》。

按照C语言的字符串函数名编写自己的函数。

在lib目录下建立了string.c 文件。

#include "string.h"
#include "global.h"
#include "debug.h"

//字符函数
//将dst_其实的size个字节置为value
void memset(void* dst_,uint8_t value,uint32_t size){
    ASSERT(dst_ != NULL);
    uint8_t* dst = (uint8_t*)dst_;  //强制类型转换
    while(size--)
        *dst++ = value;
}

//将src_起始的size个字节复制到dst_
void memcpy(void* dst_,const void* src_,uint32_t size){
    ASSERT(dst_ != NULL && src_ != NULL);
    uint8_t* dst = (uint8_t*)dst_;
    uint8_t* src = (uint8_t*)src_;
    while(size--)
        *dst++ = *src++;
}

//连续比较地址a_和地址b_开头的size个字节,若相等则返回0,大于返回1,小于返回-1
int memcmp(const char* a_,const char* b_,uint32_t size){
    const char* a = a_;
    const char* b = b_;
    ASSERT(a != NULL && b != NULL);
    while(size--){
        if(*a != *b)
            return *a > *b ? 1 : -1;
        a++;
        b++;
    }
    return 0;
}

//字符串函数
//将字符串从src_复制到dst_
//[做了修改]
char* strcpy(char* dst_,const char* src_){
    ASSERT(dst_ != NULL && src_ != NULL);
    char* temp = dst_;
    while((*temp++ = *src_++));
    return dst_;
}

//返回字符串长度
//[做了修改]
uint32_t strlen(const char* str){
    ASSERT(str != NULL);
    uint32_t len = 0;
    const char* p = str;
    while(*p++){
        len++;
    }
    return len;
}

//比较两个字符串
/* 比较两个字符串,若a_中的字符大于b_中的字符返回1,相等时返回0,否则返回-1. */
int8_t strcmp (const char* a, const char* b) {
    ASSERT(a != NULL && b != NULL);
    while (*a != 0 && *a == *b) {
        a++;
        b++;
    }
    /* 如果*a小于*b就返回-1,否则就属于*a大于等于*b的情况。在后面的布尔表达式"*a > *b"中,
    * 若*a大于*b,表达式就等于1,否则就表达式不成立,也就是布尔值为0,恰恰表示*a等于*b */
    return *a < *b ? -1 : *a > *b;
}

//从左到右查找字符串str中首次出现的字符ch的地址
char* strchr(const char* str,const uint8_t ch){
    ASSERT(str != NULL );
    while(*str != 0){
        if(*str == ch)
            return (char*)str;
        str++;
    }
    return NULL;
}

//有后向前找字符串str中首次出现字符ch的地址
char* strrchr(const char* str,const uint8_t ch){
    ASSERT(str != NULL);
    char* last_str = NULL;
    while(*str != 0){
        if(*str == ch)
            last_str = (char*)str;
        str++;
    }
    return last_str;
}

//将字符串src_拼接到dst_后,返回拼接的字符串地址
char* strcat(char* dst_,const char* src_){
    ASSERT(dst_ != NULL && src_ != NULL);
    char* p = dst_;
    while(*p++);
    p--;    //消除'\0'
    while((*p++ = *src_++));
    return dst_;
}

//在字符串str中查找字符ch出现的次数
uint32_t strchrs(const char* str,uint8_t ch){
    ASSERT(str != NULL);
    uint32_t cnt = 0;
    while(*str != 0){
        if(*str == ch)
            cnt++;
        str++;
    }
    return cnt;
}

memset函数用于内存区域的数据初始化,原理是逐字节地把value写入起始内存地址为dst_的size个空间,在本系统中通常用于内存分配时的数据清0。

memcpy 函数用于内存数据拷贝,原理是将 src_起始的 size 个字节复制到 dst_,逐字节拷贝。

memcmp函数用于一段内存数据比较,分别以两个地址a_和b_为起始,如果在size个字节内, a_中的某个内存字节的数值(或ASCI码)大于b_中同一相对位置的内存数值,此时返回1,如果这两个地址中,同一位置的所有值都相等,则返回0,否则返回-1。

strepy函数用于把起始于地址sre_的字符串复制到地址dst_,这和memepy原理相同,只不过strepy以src_处的字符’0’作为终止条件,memcpy以拷贝的字节数size为终止条件。

strlen函数用于返回字符串的长度,即字符数。

strcmp函数用于比较起始地址分别为a和b的两个字符串是否相等,若a中某个字符的ASCII值大于b 中同一相对位置字符的 ASCI 值,此时返回 1,若字符都相同,则返回 0,否则返回-1。同 memcpy的原理相同,区别就是strcmp以地址a处的字符串的长度,也就是直到字符0为终止条件,memcpy的终止条件是 size 个比对的字节。

strchr返回的是字符ch在字符串str中,从左到右最先出现的所在地址,并不是下标。

strrchr函数返回的是从后往前查找字符串str中首次出现字符ch的地址,是字符在字符串中的地址,并不是下标值。 此函数虽然是从后往前找,但原理上是通过从前往后(从左到右)的顺序查找的,这样的好处是无需事先知道字符串的结束字符0’的地址。

strcat 函数的功能是字符串拼接,将 src_处的字符串接在 dst_的结尾处,并将 dst_返回。 实现原理是将src_处的字符串拷贝到dst_的结束处。

strchrs函数用于返回字符ch在字符串str中出现的次数。

对应需要/lib/stdint.h

#ifndef __LIB_STRING_H
#define __LIB_STRING_H
#include "stdint.h"
#define NULL 0

void memset(void* dst_,uint8_t value,uint32_t size);
void memcpy(void* dst_,const void* src_,uint32_t size);
int memcmp(const char* a_,const char* b_,uint32_t size);
//[做了修改]
char* strcpy(char* dst_,const char* src_);
//[做了修改]
uint32_t strlen(const char* str);
int8_t strcmp(const char* a,const char* b);
char* strchr(const char* str,const uint8_t ch);
char* strtchr(const char* str,const uint8_t ch);
char* strcat(char* dst_,const char* src_);
uint32_t strchrs(const char* str,uint8_t ch);

#endif

 

main.c修改一下

#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
int main(void){
    put_str("I am kernel\n");
    init_all();
    ASSERT(strcmp("dreams","poems"));
    ASSERT(1==2);
    while(1);
    return 0;
}

 

makefile文件修改如下:

修改OBJS的值,加上string.o

OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o \
      $(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o \
      $(BUILD_DIR)/debug.o $(BUILD_DIR)/string.o

修改main.o,然后加上string.o

$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \
        lib/stdint.h kernel/init.h lib/string.h
    $(CC) $(CFLAGS) $< -o $@
$(BUILD_DIR)/string.o: lib/string.c lib/string.h \
    kernel/debug.h kernel/global.h
    $(CC) $(CFLAGS) $< -o $@

执行后

如果main.c换成ASSERT(strcmp(“dreams”,”dreams”));

结果如下:

 

参考

郑钢著操作系统真象还原

田宇著一个64位操作系统的设计与实现

丁渊著ORANGE’S:一个操作系统的实现

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇