memcpy、memcmp、memset、strlen、strcpy等实现

本文深入探讨了C语言中常见的字符串操作函数,如memcpy、memcmp、memset、strlen、strcpy、strcmp和strcat的实现原理与使用场景。通过具体实例,详细解析了这些函数如何高效地处理内存拷贝、比较、填充、长度计算、复制、比较和连接等任务。

1. void *memcpy(void *destin, void *source, unsigned n)

  • void memmove( void dest, const void* src, size_t count )
  • memcpy 函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中
void* user_memcpy(void *dest, const void *source, size_t n)
{
    char *d = NULL;
    const char *s = NULL;

    if (NULL == dest || NULL == source || n < 0)
    {
        return NULL;
    }

    d = (char*)dest;
    s = (const char*)source;

    // 需考虑内存存在覆盖情况 overlap
    // 1. 当源内存首地址大于目的内存首时,从低地址往高地址复制
    // 2. 当源内存首地址小于目的内存首时,从高地址往低地址复制
    // 3. 首地址相同,不做动作

    if (s > d)           //1
    {
        //正常从低地址往高地址复制
        while (n--)
        {
            *d++ = *s++;
        }
    }
    else if (d > s)      //2
    {
        //从高地址往低地址复制
        s += n - 1;
        d += n - 1;

        while (n--)
        {
            *d-- = *s--;
        }
    }
    //    else
    //    {
    //        //do nothing
    //    }
    return dest;
}
  • 上面为按byte拷贝的,在具体的平台上还可以再优化下,达到速度更快
  • memmove功能与memcpy功能差不多

2. int memcmp(const void *str1, const void *str2, size_t n))

  • 对存储区 str1 和存储区 str2 的前 n 个字节进行比较,按byte进行比较
  •   当str1 < str2 时,返回值 <0
      当str1 = str2 时,返回值 =0
      当str1 > str2 时,返回值 >0
    
int user_memcmp(void *str1, const void *str2, size_t n)
{
	assert(str1 != NULL && str2 != NULL && n > 0);

    const char *buf1 = (const char*)str1;
    const char *buf2 = (const char*)str2;

    while (n--) 
    {
        if (*buf1++ != *buf2++)
        {
            return buf1[-1] < buf2[-1] ? -1 : 1;
        }
            
    }
    return 0;
}

3. void *memset(void *s, int ch, size_t n)

  • 将某一块内存中的内容全部设置为指定的值,通常为新申请的内存做初始化工作
  • 以s为起始位置的n个字节的内存区域用整数ch进行填充
  • memset函数是以byte为单位进行赋值的
void* user_memset(void *s, int ch, size_t n)
{
    char* tmp = NULL;

    if (s == NULL || n < 0)
    {
        return NULL;
    }

    tmp = (char*)s;

    while (n--)
    {
        *tmp++ = ch;
    }
    return s;
}

4. size_t strlen(const char *string)

  • 功能是计算字符串的实际长度。从string起始地址往后查找,直到查找到’\0’时停止,如果string里没有’\0’,会继续找下去,直到遇到’\0’停止。返回长度不包括 ‘\0’ 。
size_t user_strlen(const char *src)
{
    size_t len = 0;
    const char* tmp = NULL;
    assert(src);

    tmp = src;
    while (*tmp++ != '\0')
    {
        len++;
    }
    return len;
}

5. char *strcpy(char dest, const char *src)

  • 把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间
  • src 和 dest 所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串
char *user_strcpy(char *dest, const char *src)
{
    char* d = NULL;
    const char* s = NULL;

    assert(dest && src);

    d = dest;
    s = src;

    while(*d++ = *s++);

    return dest;
}

6. int strcmp(const char *s1, const char *s2)

  • strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数
  • 若str1=str2,则返回值 =0
  • 若str1<str2,则返回值 <0
  • 若str1>str2,则返回值 >0
int user_strcmp(const char *s1, const char* s2)
{
    int ret = 0;

    while( !(ret = *(unsigned char*)s1 - *(unsigned char*)s2) && *s1 )
    {
        s1++;
        s2++;
    }

    if(ret < 0)
    {
        return -1;
    }
    else if(ret > 0)
    {
        return 1;
    }
    return 0;
}

7. char *strcat(char *dest, const char *src)

  • 把src所指向的字符串 (包括 ‘\0’ )复制到dest所指向的字符串后面(删除*dest原来末尾的 ‘\0’ )
  • 要保证dest足够长,以容纳被复制进来的src
  • *src中原有的字符不变。返回指向dest的指针
char* user_strcat(char *dest, char *src)
{
    char *d = NULL;
    char *s = NULL;

    assert(dest && src);
    d = dest;
    s = src;

    while(*d)
    {
        d++;
    }

    while(*d++ = *s++);

    return dest;
}
在 Linux 内核编程中,**不能直接使用标准 C 库函数**(如 `memcmp`、`memcpy`、`printf`、`malloc` 等),因为内核环境与用户空间有很大不同。但内核提供了**等价的替代函数**,用于完成相同的功能。 --- ## 一、`memcmp` 在内核中可以使用吗? ### ❌ 不能直接使用标准库的 `memcmp` - `memcmp` 是标准 C 库(glibc)提供的函数,运行在用户空间。 - 内核没有链接 glibc,因此不能直接使用 `memcmp`。 ### ✅ 可以使用内核提供的替代函数:`memcmp` Linux 内核中其实**定义了自己的 `memcmp` 实现**,位于源码中的 `lib/string.c` 文件中: ```c int memcmp(const void *cs, const void *ct, size_t count) ``` 所以你可以直接在内核模块中使用 `memcmp` 函数,它的行为与用户空间的 `memcmp` **完全一致**。 --- ## 二、`memcpy` 在内核中可以使用吗? ### ❌ 不能直接使用标准库的 `memcpy` - 同样,标准库的 `memcpy` 不能在内核中使用。 - 内核中没有 glibc,也没有完整的 C 标准库支持。 ### ✅ 可以使用内核提供的替代函数:`memcpy` 内核也提供了自己的 `memcpy` 实现: ```c void *memcpy(void *dest, const void *src, size_t count) ``` 这个函数在内核中可以直接使用,功能与用户空间的 `memcpy` 完全一致。 --- ## 三、为什么不能直接使用标准库函数? | 原因 | 说明 | |------|------| | 1. 内核没有 libc | 内核是操作系统的核心,不能依赖用户空间的库(如 glibc) | | 2. 编译环境不同 | 内核使用特殊的编译器标志和链接器脚本,不链接标准库 | | 3. 函数行为可能不同 | 标准库函数可能依赖系统调用(如 `malloc` 依赖 `brk` 或 `mmap`) | | 4. 性能优化 | 内核函数针对特定架构优化(如 ARM、x86) | | 5. 安全性 | 内核函数避免使用可能触发异常的代码路径 | --- ## 四、内核中常用的内存操作函数(替代标准库) | 标准库函数 | 内核替代函数 | 头文件 | |------------|---------------|--------| | `memcpy` | `memcpy` | `<linux/string.h>` | | `memcmp` | `memcmp` | `<linux/string.h>` | | `memset` | `memset` | `<linux/string.h>` | | `memmove` | `memmove` | `<linux/string.h>` | | `strcpy` | `strcpy` | `<linux/string.h>` | | `strcmp` | `strcmp` | `<linux/string.h>` | | `strlen` | `strlen` | `<linux/string.h>` | --- ## 五、使用示例 ### 示例 1:使用 `memcmp` 比较两个内存块 ```c #include <linux/module.h> #include <linux/string.h> static int __init my_init(void) { char a[10] = "hello"; char b[10] = "hello"; if (memcmp(a, b, 6) == 0) printk(KERN_INFO "a and b are equal\n"); else printk(KERN_INFO "a and b are not equal\n"); return 0; } static void __exit my_exit(void) { printk(KERN_INFO "Module exited\n"); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL"); ``` ### 示例 2:使用 `memcpy` 拷贝内存 ```c #include <linux/module.h> #include <linux/string.h> static int __init my_init(void) { char src[10] = "hello"; char dest[10]; memcpy(dest, src, 6); printk(KERN_INFO "Copied string: %s\n", dest); return 0; } static void __exit my_exit(void) { printk(KERN_INFO "Module exited\n"); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL"); ``` --- ## 六、总结对比 | 函数 | 用户空间 | 内核空间 | 是否可用 | 说明 | |------|----------|----------|----------|------| | `memcpy` | ✅ 是 | ✅ 是(内核实现) | ✅ 可用 | | `memcmp` | ✅ 是 | ✅ 是(内核实现) | ✅ 可用 | | `malloc` | ✅ 是 | ❌ 否 | ❌ 不可用 | 使用 `kmalloc` 替代 | | `printf` | ✅ 是 | ❌ 否 | ❌ 不可用 | 使用 `printk` 替代 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值