比较两个指针是否不仅仅是检查它们的地址?
Does comparing two pointers do more than to just check their adresses?
我正在重写 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
和 [=15= 的大小时才有意义] 就我的理解而言,这是不正确的。那么这个比较除了检查地址的位置之外还有什么作用吗?还是我对指针的理解完全错误?
这段代码有什么用处吗?如果我完全错误,请提前抱歉,指针可能会非常混乱。
函数 memmove 假定源数组和目标数组重叠。那就是它们是指向同一数组不同部分的指针。
因此,例如这个 if 语句
if (d < s)
检查数组中指针d指向的元素是否在指针s指向的元素之前。
考虑一个例子。假设声明了一个数组
char s[] = "Hello World!";
即数组包含字符串"Hello World!"
。并且您想更改数组,使其包含字符串“World!”。您需要的是移动源字符串中包含子字符串“World!”的部分。到数组的开头。
如果你会写
strcpy( s, s + 6 );
那么这样的调用会调用未定义的行为,因为函数 strcpy 不允许使用重叠的子数组。
使用 memmove 你可以写
memmove( s, s + 6, 7 );
在这种情况下,相对于您提供的函数定义,指针 d 具有原始数组 s 的值,指针 s 具有等于表达式 s + 6 的值。
由于d的值小于指针s的值,所以这部分函数获得了控制权
if (d < s)
while (n--)
*d++ = *s++;
注意按照C标准(6.5.8关系运算符)
5 When two pointers are compared, the result depends on the relative
locations in the address space of the objects pointed to. If two
pointers to object types both point to the same object, or both point
one past the last element of the same array object, they compare
equal. If the objects pointed to are members of the same aggregate
object, pointers to structure members declared later compare
greater than pointers to members declared earlier in the structure,
and pointers to array elements with larger subscript values compare
greater than pointers to elements of the same array with lower
subscript values. All pointers to members of the same union object
compare equal. If the expression P points to an element of an
array object and the expression Q points to the last element of the
same array object, the pointer expression Q+1 compares greater than P.
In all other cases, the behavior is undefined.
从引用中可以看出,传递给函数 memmove 的两个指针应指向同一数组的元素,以保证此 if 语句中指针比较的定义行为
if (d < s)
否则行为未定义。
is this comparison doing anything besides checking the position of the addresses?
没有。它检查 d
的地址是否低于 s
。如果是,则选择第一种策略,从内存区域的开头向前复制-否则从内存区域的末尾向后复制
这是为了避免在 [d,d+n)
和 [s,s+n)
重叠的情况下弄乱结果。
示例:
+---+---+---+
src | x | y | z |
+---+---+---+---+
dest | | | |
+---+---+---+
^ ^
| |
low mem addr high mem addr
这里必须选择第二种策略。考虑一下如果选择第一个策略会发生什么:
dest[0] = src[0]; // which is x
dest[1] = src[1]; // which is ... x, because the above op overwrote the y
我正在重写 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
和 [=15= 的大小时才有意义] 就我的理解而言,这是不正确的。那么这个比较除了检查地址的位置之外还有什么作用吗?还是我对指针的理解完全错误?
这段代码有什么用处吗?如果我完全错误,请提前抱歉,指针可能会非常混乱。
函数 memmove 假定源数组和目标数组重叠。那就是它们是指向同一数组不同部分的指针。 因此,例如这个 if 语句
if (d < s)
检查数组中指针d指向的元素是否在指针s指向的元素之前。
考虑一个例子。假设声明了一个数组
char s[] = "Hello World!";
即数组包含字符串"Hello World!"
。并且您想更改数组,使其包含字符串“World!”。您需要的是移动源字符串中包含子字符串“World!”的部分。到数组的开头。
如果你会写
strcpy( s, s + 6 );
那么这样的调用会调用未定义的行为,因为函数 strcpy 不允许使用重叠的子数组。
使用 memmove 你可以写
memmove( s, s + 6, 7 );
在这种情况下,相对于您提供的函数定义,指针 d 具有原始数组 s 的值,指针 s 具有等于表达式 s + 6 的值。
由于d的值小于指针s的值,所以这部分函数获得了控制权
if (d < s)
while (n--)
*d++ = *s++;
注意按照C标准(6.5.8关系运算符)
5 When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object types both point to the same object, or both point one past the last element of the same array object, they compare equal. If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal. If the expression P points to an element of an array object and the expression Q points to the last element of the same array object, the pointer expression Q+1 compares greater than P. In all other cases, the behavior is undefined.
从引用中可以看出,传递给函数 memmove 的两个指针应指向同一数组的元素,以保证此 if 语句中指针比较的定义行为
if (d < s)
否则行为未定义。
is this comparison doing anything besides checking the position of the addresses?
没有。它检查 d
的地址是否低于 s
。如果是,则选择第一种策略,从内存区域的开头向前复制-否则从内存区域的末尾向后复制
这是为了避免在 [d,d+n)
和 [s,s+n)
重叠的情况下弄乱结果。
示例:
+---+---+---+
src | x | y | z |
+---+---+---+---+
dest | | | |
+---+---+---+
^ ^
| |
low mem addr high mem addr
这里必须选择第二种策略。考虑一下如果选择第一个策略会发生什么:
dest[0] = src[0]; // which is x
dest[1] = src[1]; // which is ... x, because the above op overwrote the y