走进C标准库(7)——"string.h"中函数的实现memcmp,memcpy,memmove,memset

本文详细解析了C语言中memcmp、memcpy、memmove及memset四个内存操作函数的实现原理及区别,尤其强调了memcpy和memmove在处理内存重叠情况下的不同表现。

我的memcmp:

 1 int memcmp(void *buf1, void *buf2, unsigned int count){
 2     int reval;
 3     while(count && !(reval = (*(unsigned char *)buf1) - (*(unsigned char *)buf2)))
 4     {
 5         buf1 = (unsigned char *)buf1 + 1;
 6         buf2 = (unsigned char *)buf2 + 1;
 7         --count;
 8     }
 9     return reval;
10 }

MS VC:

int __cdecl memcmp (
        const void * buf1,
        const void * buf2,
        size_t count
        )
{
        if (!count)
                return(0);

        while ( --count && *(char *)buf1 == *(char *)buf2 ) {
                buf1 = (char *)buf1 + 1;
                buf2 = (char *)buf2 + 1;
        }

        return( *((unsigned char *)buf1) - *((unsigned char *)buf2) );
}

应该使用const void *buf为宜,不改变该块内存的内容,最终使用unsigned char *进行运算,保证运算结果的符号正确。

 

我的memcpy:

1 void *memcpy(void *dest, const void *src, unsigned int count){
2     void *reval = dest;
3     while(count--){
4          (*(unsigned char *)dest++) = (*(unsigned char *)src++);
5     }
6     return reval;
7 }

MSVC:

 1 void * __cdecl memcpy (
 2         void * dst,
 3         const void * src,
 4         size_t count
 5         )
 6 {
 7         void * ret = dst;
 8 
 9 #if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
10         {
11         extern void RtlMoveMemory( void *, const void *, size_t count );
12 
13         RtlMoveMemory( dst, src, count );
14         }
15 #else  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
16         /*
17          * copy from lower addresses to higher addresses
18          */
19         while (count--) {
20                 *(char *)dst = *(char *)src;
21                 dst = (char *)dst + 1;
22                 src = (char *)src + 1;
23         }
24 #endif  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
25 
26         return(ret);
27 }

 

我的memmove:

 1 void *memmove(void *dest, const void *src, unsigned int count){
 2     void *reval = dest;
 3     int overlap = ((unsigned char *)src < (unsigned char *)dest && ((unsigned char *)src + count) > dest);
 4     while(count--){
 5         if(overlap)//src is in front of dest and overlap. copy direction is from endIndex to beginIndex
 6               (*((unsigned char *)dest + count)) = (*((unsigned char *)src + count));
 7         else
 8             (*(unsigned char *)dest++) = (*(unsigned char *)src++);
 9     }
10     return reval;
11 }

MSVC:

 1 void * __cdecl memmove (
 2         void * dst,
 3         const void * src,
 4         size_t count
 5         )
 6 {
 7         void * ret = dst;
 8 
 9 #if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
10         {
11         extern void RtlMoveMemory( void *, const void *, size_t count );
12 
13         RtlMoveMemory( dst, src, count );
14         }
15 #else  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
16         if (dst <= src || (char *)dst >= ((char *)src + count)) {
17                 /*
18                  * Non-Overlapping Buffers
19                  * copy from lower addresses to higher addresses
20                  */
21                 while (count--) {
22                         *(char *)dst = *(char *)src;
23                         dst = (char *)dst + 1;
24                         src = (char *)src + 1;
25                 }
26         }
27         else {
28                 /*
29                  * Overlapping Buffers
30                  * copy from higher addresses to lower addresses
31                  */
32                 dst = (char *)dst + count - 1;
33                 src = (char *)src + count - 1;
34 
35                 while (count--) {
36                         *(char *)dst = *(char *)src;
37                         dst = (char *)dst - 1;
38                         src = (char *)src - 1;
39                 }
40         }
41 #endif  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
42 
43         return(ret);
44 }

关于memcpy和memmove的区别,memcpy不考虑内存区域重叠的情况而memmove保证内存区域重叠也能正常复制成功。

有时候我们的memcpy也可能在内存重叠的情况下正常使用,这取决于它的实现,不具有普遍性,C语言标准中未对其有这种要求。

参考资料:

《关于memcpy和memmove两函数的区别》

http://blog.youkuaiyun.com/caowei840701/article/details/8491836

《memcpy() vs memmove()》  

http://stackoverflow.com/questions/4415910/memcpy-vs-memmove

 

我的memset:

1 void *memset(void *buffer, int c, int count){
2     void *reval = buffer;
3     while(count--){
4         (*(unsigned char *)buffer++) = (unsigned char)c;
5     }
6     return reval;
7 }

MSVC:

 1 void * __cdecl memset (
 2         void *dst,
 3         int val,
 4         size_t count
 5         )
 6 {
 7         void *start = dst;
 8 
 9 #if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
10         {
11         extern void RtlFillMemory( void *, size_t count, char );
12 
13         RtlFillMemory( dst, count, (char)val );
14         }
15 #else  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
16         while (count--) {
17                 *(char *)dst = (char)val;
18                 dst = (char *)dst + 1;
19         }
20 #endif  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
21 
22         return(start);
23 }

 

转载于:https://www.cnblogs.com/shijiezhenmei/p/3701551.html

### C语言中字符串处理函数的操作数据类型及区别 #### 数据类型概述 这些函数主要操作的是指针类型的参数,具体来说是指向`void`、指向特定基本数据类型(如`char`)、以及整数计数值。对于`memcpy`、`memmove`和`memset`而言,其工作对象是内存中的字节序列;而对于`memcmp`则是用于比较两个指定长度的内存区域的内容;至于`strcpy`与`strncpy`则专门针对以null终止符结尾的字符串进行复制。 #### memcpymemmove 的功能对比 - `memcpy`负责将源地址所指向的一块连续存储区内容复制到目标位置处[^1]。 - 当涉及到有重叠部分的记忆体区间转移时,则应该采用`memmove`来代替前者,因为后者能够正确处理这种情况下的数据迁移问题[^2]。 ```c // 示例:使用memcpy可能导致未定义行为的情况 #include <stdio.h> #include <string.h> int main() { int arr[] = { 1, 2, 3, 4, 5 }; // 这里如果arr+1和arr之间存在重叠可能会出现问题 memcpy(arr, arr + 1, sizeof(int) * 4); for (size_t i = 0; i < 5; ++i){ printf("%d ", arr[i]); } } ``` #### memset 的应用范围 此函数用来填充一块已分配好的内存量至给定值,通常应用于初始化数组或结构体成员变量为某个固定不变的状态,比如全部置零或者设置成其他特殊标记位[^3]。 ```c #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include< string .h> int main(){ char str[ ]="hello world"; // 将前六个字符替换为'x' memset(str,'x',6*sizeof(char)); puts(str); } ``` #### memcmp 的作用机制 通过逐个比较两段相同大小的缓冲区内每一个对应的字节差异情况返回一个相对应的结果码(-1/0/+1),可用于判断两者是否相等或是哪一方更大一些。 #### strcpy 及 strncpy 特征分析 这两个都是为了完成字符串之间的赋值而设计出来的标准库接口之一,不同之处在于后者允许设定最大拷贝数量从而防止溢出风险的发生,并且会在必要时候自动补充结束标志'\0'[ ^4]. ```c #include<stdio.h> #include<string.h> int main(){ char sourceStr[]= "example text."; char targetStr[20]; // 安全地复制不超过9个字符(含\0) strncpy(targetStr,sourceStr ,9); // 显示最终结果 printf("Copied String is %s\n",targetStr ); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值