代码、内容参考来自于包括《操作系统真象还原》、《一个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:一个操作系统的实现


