2013-10-26 3 views
5

私はwikibooks.orgでパブリックドメインの実装を検討していました。 memmove()は、 "完全に移植可能"ではないことを明示的に示しています。私は理由として思っていた:memmoveの実装について

  1. 括弧は、コードの最初の行に配置し、そして
  2. コードは、完全にポータブルではありません。次のよう

コードは次のとおりです。

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; 
} 
+3

良い質問は、[関数名のかっこはどういう意味ですか?](http://stackoverflow.com/questions/13600790/what-do-the-parentheses-around-a-function-name-mean/ 13600837#13600837) –

+0

ありがとう、それは便利でした! – user926918

答えて

9

機能memmove()の仕様は、それがオーバーラップする送信元と宛先を扱うことができるということですが、仕様がmemmove()はへのポインタで呼び出さなければならないことを言っていません。同じメモリブロック(標準の用語では「オブジェクト」)。

p1p2が異なるメモリブロックへのポインタである場合は、条件p2 < p1未定義の動作です。 C99標準では(6.5.8:5):言う二つのポインタを比較すると

、結果が指し示さオブジェクトのアドレス空間内の相対 位置に依存します。 2つの オブジェクト型または不完全型へのポインタが両方とも同じオブジェクト(同じ配列オブジェクトの最後の要素を越えて同じオブジェクト、 または両方を指す場合)を指す場合、それらは と等しくなります。指し示されたオブジェクトが同じ 集約オブジェクトのメンバである場合、後で宣言された構造体メンバへのポインタ 構造体の前に宣言されたメンバへのポインタよりも大きい値と添字値が大きい配列要素へのポインタ は、同じ配列の添え字値は です。同じユニオンオブジェクトのメンバーへのすべてのポインタ は同等です。式Pが配列 オブジェクトの要素を指し、式Qが同じ 配列オブジェクトの最後の要素を指している場合、ポインタ式Q + 1はPよりも大きくなります。 他のすべての場合、その動作は未定義です。

私はこれが説明の意味であるかどうかわかりませんが、移植性のない明確な情報源の1つです。

異なる実装では(uintptr_t)p2 < (uintptr_t)p1を使用することがあります。次に、比較<は整数の比較です。 uintptr_tに変換すると、実装定義の結果が得られます。 uintptr_t型はC99で導入され、ポインタの表現を保持することが保証されている符号なし整数型です。

memmove()の完全移植可能な実装では、中間コピーを保持するために3番目のバッファ、またはuse == comparison(使用する必要のあるコンテキストで指定された結果を与える)を使用することがあります。

5
  1. 括弧の説明はここにある:What do the parentheses around a function name mean?

  2. それが原因p2 < p1p1 < p2 + n比較のポータブルではありません。Cの標準では、2つのポインタが同じオブジェクトを指しているときのポインタ比較の動作しか定義していません。このコードは、異なるオブジェクト間でコピーしている場合でも、合理的に動作するかどうかによって異なります。

実用的な意味では、コードは問題ありません。ポインターが同じオブジェクトを指していないときは、コピーが昇順であるか降順であるかは関係ありませんので、比較の結果は関係ありません。重要なことは、コードがプロセスをクラッシュさせたり、核打ち出しコードを送信したりするような、本当に恐ろしいことをしないということです。 Cの標準はこれを禁止していませんが、現実的な実装ではそうではありません。ほとんどの実装は生のアドレスを単純に比較しますが、奇妙な実装は予測できない値を返すだけですが、副作用はありません。

+1

フラットなアドレス空間を持つ最新のプラットフォームではコードは問題ありません。 Steve Jessopは、私の古い質問に対する彼の答えの中でC++の 'std :: less'をよく説明しています(私はこの質問に私の答えでリンクしました)。 –

関連する問題