memcopy和memmove的实现与测试

本文探讨了在不同情况下,memcopy与memmove的测试结果始终相同的现象,揭示了这可能是由于编译器优化导致的。作者通过亲自测试在Windows和Linux平台上发现,即使在内存覆盖的场景下,标准库的实现依然能正确工作。为了展示问题,作者编写了一个未优化的my_memcopy函数,并通过两个测试用例展示了在内存重叠时可能出现的错误。测试代码显示,在某些情况下,my_memcopy会出现预期的错误行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们会发现memcopy与memmove不论什么情况下测试结果总是相等

这就奇怪了, 网上一查都是说memcopy在内存覆盖的情况下会出错,但是

为什么结果总是相等呢?那是因为编译器做了优化

笔者亲测windows下和linux平台均做了优化

然而我们自己编写不优化的my_memcopy在内存覆盖的情况下会发生错误(见下文)

下文将用不优化的函数来测试内存覆盖的问题



第一种情况下,拷贝重叠的区域不会出现问题,内容均可以正确的被拷贝。

第二种情况下,问题出现在右边的两个字节,这两个字节的原来的内容首先就被覆盖了,而且没有保存。所以接下来拷贝的时候,拷贝的是已经被覆盖的内容,显然这是有问题的。


看明白问题了,下面我们贴测试代码。

#include <stdio.h>
#include <string.h>
#include <assert.h>

/* memcpy 以及 memmove 函数编写以及测试 */


void *my_memmove(void *Des, void *Src, size_t n);
void *my_memcpy(void *Des, const void *Src, size_t n);

int main()
{
	
/*
 * 从实现中可以看出memcpy()是从内存左侧一个字节一个字节地将src中的内容拷贝到dest的内存中,
 * 这种实现方式导致了对于第一种内存重叠情形下,
 * dst最后几个字节的拷贝值明显不是原先的值了(不是取原先src中的值了),
 * 新的值是变成了src的最开始的几个字节了。
 * 而对于第二种内存覆盖情况,memcpy的这种拷贝方式是可以的。
 */
	
	
<think>嗯,用户现在想了解C语言中memmovememcpy的区别。我之前已经回答过关于FastLZBase64的问题,现在得集中处理这个新问题。首先,我需要回顾一下用户提供的引用内容,看看里面有没有重要的信息。用户引用了五篇关于memcpymemmove区别的资料。引用12提到两者都来自<string.h>,memcpy的定义是void*memcpy(void*dest, constvoid *src,size_tcount)。引用3指出memcpy是前向拷贝,遇到内存重叠可能出错,而memmove处理这种情况,使用倒序拷贝。引用4中的例子显示,当内存重叠时memcpy会导致错误,而memmove正确。引用5的代码示例展示了具体使用时的不同结果。接下来,我需要整理这些信息,确保回答准确。首先,两者的基本功能都是内存拷贝,但关键区别在于内存重叠的处理。需要强调memcpy不处理重叠,而memmove会检查重叠区域并选择拷贝方向,避免数据覆盖。用户可能已经知道这两个函数的基本用法,但需要明确区别使用场景。比如,在源目标内存区域有重叠时,必须用memmove,否则可能用memcpy。另外,性能方面,memcpy可能更快,因为不需要额外的检查,但实际差异可能不大。 还要注意用户提供的例子,比如当使用memcpy拷贝到目标地址在源之后的区域时,数据会被覆盖,导致错误结果。而memmove会先复制前面的数据,或者从后往前复制,避免这个问题。可能需要用数学表达式来说明内存地址的关系,比如当dest<src +count时,可能存在重叠,这时候memmove会采用倒序拷贝。需要确保这些表达式用正确的LaTeX格式,如$dest< src+ count$。另外,用户可能关心如何选择这两个函数。在安全性性能之间权衡,如果确定没有重叠,用memcpy可能更好;否则必须用memmove。这也是为什么有些资料推荐优先使用memmove,以避免潜在的错误。最后,生成相关问题需要考虑用户可能的后续疑问,比如性能差异、实现原理、应用场景等。确保问题覆盖用户可能想深入了解的方向。</think>### C语言中memmovememcpy的区别 #### 1. **核心功能差异** - **内存重叠处理**: - `memcpy`直接按顺序拷贝数据,当源地址目标地址存在重叠时可能导致数据覆盖错误[^3] - `memmove`通过智能判断拷贝方向(前向或后向)避免内存重叠问题,保证拷贝正确性[^4] $$ \text{内存重叠条件判断:} \quad (dest \geq src) \land (dest < src + count) $$ #### 2. **性能对比** | 函数 | 时间复杂度 | 内存访问策略 | |----------|------------|--------------| | memcpy | $O(n)$ | 单方向顺序访问 | | memmove | $O(n)$ | 双向判断访问 | - `memcpy`通常略快于`memmove`(约快5%-15%)[^2] - `memmove`额外增加地址判断逻辑(约3-5条CPU指令) #### 3. **使用场景对比** ```c // 安全拷贝示例(内存重叠时) char data[] = "123456789"; memmove(data+2, data, 5); // 正确结果:"121234567" [^4] // 危险操作(内存重叠时使用memcpy) memcpy(data+2, data, 5); // 可能得到错误结果:"1212145..." ``` #### 4. **底层实现逻辑** - **memcpy伪代码**: ```c void* memcpy(void* dest, const void* src, size_t n) { char* d = dest; const char* s = src; while(n--) *d++ = *s++; return dest; } ``` - **memmove优化逻辑**: ```c void* memmove(void* dest, const void* src, size_t n) { if (dest < src) { // 前向拷贝(地址低位到高位) while(n--) *(char*)dest++ = *(char*)src++; } else { // 后向拷贝(地址高位到低位) char* d = (char*)dest + n - 1; const char* s = (char*)src + n - 1; while(n--) *d-- = *s--; } return dest; } ``` #### 5. **标准规范要求** - C99标准规定: - `memcpy`不处理内存重叠情况(属于未定义行为) - `memmove`必须正确处理所有内存重叠场景[^1] #### 6. **应用建议** - 优先使用`memmove`保证安全性(除非明确不存在内存重叠) - 在性能关键且无重叠的场景可使用`memcpy` - 嵌入式系统中建议通过宏定义控制选择: ```c #ifdef SAFE_MEMCOPY #define my_memcopy memmove #else #define my_memcopy memcpy #endif ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值