【发布时间】:2021-12-10 21:43:12
【问题描述】:
我正在重写 libc 的一部分,更具体地说 memmove 作为一个练习,在我自己无法做到之后,我查找了它的源代码并找到了这个(以及它的变体):
void *memmove(void *dest, const void *src, size_t n)
{
char *d = dest;
const char *s = src;
if (d < s)
while (n--)
*d++ = *s++;
else
{
char *lasts = s + (n-1);
char *lastd = d + (n-1);
while (n--)
*lastd-- = *lasts--;
}
return (dest);
}
我的问题涉及第 5 行 if (d < s) 对我来说,这只有在 d 和 s 包含 dest 和 src 的大小时才有意义,据我所知这是不正确的。那么除了检查地址的位置之外,这种比较还有其他作用吗?还是我对指针的理解完全有缺陷?
这段代码有什么用途吗?如果我完全错了,请提前抱歉,指针可能会很混乱。
【问题讨论】:
-
指针不包含它所指向的对象的长度。进行此检查的原因是因为参数可能重叠。为了确保来自
src的数据在被复制之前不会被覆盖,算法会检查dest是在src的左侧还是右侧。如果dest在左侧,则从左侧开始复制,然后沿着src和dest向右移动。如果是向右,则从右侧开始复制,向左移动。 -
@LouisCloete 是堆中的地址还是栈中的地址?
-
@MiguelP 没关系。
-
请注意,库例程的实现使用了 C 标准未在普通用户代码中定义的比较。只有当
d和s指向同一个数组时,C 标准才定义d < s,包括最后一个数组元素之后的名义位置。但是,即使d和s指向完全不同的对象,标准库函数memmove也必须能够工作。这使得使用严格符合 C 代码的memmove无法实现;它必须依赖编译器来定义d < s,即使 C 标准没有。 -
@EricPostpischil
(uintptr_t)d < (uintptr_t)s在大多数系统上给出了合理的结果。
标签: c performance pointers c-strings memmove