关于memmove的实现

时间:2013-10-26 11:56:17

标签: c portability memmove

我在查看wikibooks.org上的公共域实现。它实现了memmove(),如下明确声明它“不完全可移植”!我想知道为什么:

  1. 括号放在代码的第一行,
  2. 代码不是完全可移植的。
  3. 代码如下:

    void *(memmove)(void *s1, const void *s2, size_t n)
    {
       char *p1 = s1;
       const char *p2 = s2;
    
       if (p2 < p1 && p1 < p2 + n) {
           /* do a descending copy */
           p2 += n;
           p1 += n;
           while (n-- != 0)
               *--p1 = *--p2;
       } else
           while (n-- != 0)
               *p1++ = *p2++;
    
       return s1;
    }
    

2 个答案:

答案 0 :(得分:9)

函数memmove()的规范是它可以处理重叠的源和目标,但规范并没有说必须使用指向同一内存块(“对象”)的指针调用memmove()标准的说法。

p1p2是指向不同内存块的指针时,条件p2 < p1未定义的行为。 C99标准说(6.5.8:5):

  

当比较两个指针时,结果取决于相对值   指向的对象的地址空间中的位置。如果两个   指向对象或不完整类型的指针都指向同一个对象,   或者两者都指向同一个数组对象的最后一个元素,它们   比较平等。如果指向的对象是同一个成员   聚合对象,指向稍后声明的结构成员的指针   大于指向结构中先前声明的成员的指针,   和指向具有较大下标值的数组元素的指针进行比较   大于指向同一数组元素的指针   下标值。指向同一个union对象的成员的所有指针   比较平等。如果表达式P指向数组的元素   对象和表达式Q指向同一个的最后一个元素   数组对象,指针表达式Q + 1比较大于P.   在所有其他情况下,行为未定义。

我不知道这是否是解释所指的内容,但它是不可移植性的明确来源。

其他实现可能会使用(uintptr_t)p2 < (uintptr_t)p1。然后比较<是整数之间的比较。转换为uintptr_t可提供实现定义的结果。类型uintptr_t是在C99中引入的,是一种无符号整数类型,保证保存指针的表示。

memmove()的完全可移植实现可能使用第三个缓冲区来保存中间副本,或use == comparison(在必须使用它的上下文中给出指定结果)。

答案 1 :(得分:5)

  1. 括号的解释如下:What do the parentheses around a function name mean?

  2. 由于p2 < p1p1 < p2 + n比较,它无法移植。当两个指针指向同一个对象时,C标准仅定义指针比较的行为。即使您在不同对象之间进行复制,此代码依赖于它们合理地工作。

  3. 实际上,代码很好。当指针不指向同一个对象时,复制是上升还是下降并不重要,因此比较结果无关紧要。重要的是代码不会做一些非常可怕的事情,比如崩溃过程或发送核启动代码。 C标准并没有禁止这一点,但它不可能在任何实际的实现中。大多数实现只是比较原始地址,任何奇怪的实现只会返回一个不可预测的值,但没有任何副作用。