源码中几个字符串函数的优雅实现

以下是linux内核源码中的实现,与GNU C标准库是略有出入的:
————
strcpy:

char *strcpy(char *dest, const char *src)
{
    char *tmp = dest;

    while ((*dest++ = *src++) != '\0')
        /* nothing */;
    return tmp;
}

在string.h中字符串处理函数基本上都不会帮你检查是否越界的问题,所以比如这一个在使用时就得保证dest这个指针指向了足够容纳src的空间(当然dest,src也都不能是NULL),否则会出现不可预知的错误。
同时while ((*dest++ = *src++) != '\0');是一个非常地道的C风格的实现,括号中返回的是左值,最后判断是否是’\0’。
第二个参数const char*,显然我们不希望这个函数改变源字符串的内容。
返回值是char *类型,返回的是最后的dest,链式操作的实现。
用一个tmp变量保存dest字符串的首地址(中间修改了dest,所以不能拿它当返回值了),用来当函数返回值。
————
strncpy

char *strncpy(char *dest, const char *src, size_t count)
{
    char *tmp = dest;

    while (count) {
        if ((*tmp = *src) != 0)
            src++;
        tmp++;
        count--;
    }
    return dest;
}

不得不说这段代码写的很赞。

while (count) {
    if ((*tmp = *src) != 0)
        src++;
    tmp++;
    count--;
}

上面这一段用最简洁的方法实现了这么个熟知的逻辑,strncpy有个参数n规定了最大复制的字符数,现在把src逐个赋给dest,这时候如果src太短,长度小于n的值,那么dest后面都将是\0。
Example:
src: H e l l o \0
n: 8
tmp: H e l l o \0 \0 \0
————
strchr

char *strchr(const char *s, int c)
{
    for (; *s != (char)c; ++s)
        if (*s == '\0')
            return NULL;
    return (char *)s;
}

返回string中第一次出现某个char的地址。
第二个参数是int?我谷歌了可能是历史原因,stackoverflow上有一些参考,不保证正确:Why does strchr take an int for the char to be found?
如果没找到c的话,会返回NULL。
————
strcmp

int strcmp(const char *cs, const char *ct)
{
    unsigned char c1, c2;

    while (1) {
        c1 = *cs++;
        c2 = *ct++;
        if (c1 != c2)
            return c1 < c2 ? -1 : 1;
        if (!c1)
            break;
    }
    return 0;
}

c1 = *cs++是一个简单的逻辑,先把*cs的值赋值给c1,然后cs指针后移。
————
strlen

size_t strlen(const char *s)
{
    const char *sc;

    for (sc = s; *sc != '\0'; ++sc)
        /* nothing */;
    return sc - s;
}

神奇的算偏移量而不是用count计数,同时确认了strlen算长度是不包括字符串尾部的’\0’的。
————
懒了,别的不看了,基本上也就是这几个类似的指针运算的tricks。

Tags :

0 thoughts on “源码中几个字符串函数的优雅实现”

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Click the right image To submit your comment: