4

コードに次のようなものがある場合:

void f(struct foo *x, struct foo *y)
{
  *x = *y; // structure copy (memcpy?)
}

x と y が同じアドレスを指している場合、どうなりますか?

これは有効なコードですか? また、コンパイラが代入を、潜在的に無効なオペランドを含む memcpy 呼び出しに変換するとどうなりますか (オーバーラップは許可されません)。

[はい、この場合「restrict」を使用できることはわかっていますが、これを考慮した実際のコードは bison によって自動的に生成されたものであるため、常に有効である必要があるかどうか、およびコンパイラが memmove を使用するか、オーバーラップを許可する他の何か..]

4

4 に答える 4

3

構造体の代入は完全に合法です。したがって、コンパイラは正しいコードを生成します (コンパイラのバグにもかかわらず)。

于 2011-01-19T12:23:59.043 に答える
1

これは私には完全に有効に見えます。はい、これは一種のmemcpy.

likeへの 2 つのポインターstructは、同じであるか、まったく重複してはなりません。したがって、前にポインターが等しいかどうかを確認できます。

(確かにコードをだまして実際にオーバーラップさせることはできますが、それには本当に特別な理由が必要です。)

于 2011-01-19T11:03:15.960 に答える
0

これは有効なコードです。コンパイラは x != y を想定できないため、安全な memmove を使用する必要があります。

于 2011-01-19T12:31:26.650 に答える
0

[はい、標準を少し調べて、ここで関連する質問をさらに検索した後、これを見たので、自分の質問に答えます]

実際、これは、fd_set (select() または pselect() の場合) で構造体のコピーを使用すると問題が発生するプラットフォームはありますか?への回答の一部によって回答されています。(この回答では)、ここに貼り付けます:

次のいずれかが成り立つ:

...

左のオペランドには、右の型と互換性のある構造体または共用体型の修飾または非修飾バージョンがあります。

...

オブジェクトに格納されている値が、最初のオブジェクトのストレージとオーバーラップする別のオブジェクトから読み取られる場合、オーバーラップは正確であり、2 つのオブジェクトは互換性のある型の修飾バージョンまたは非修飾バージョンを持つ必要があります。それ以外の場合、動作は未定義です。

したがって、ポインターが同じである限り (つまり、完全にオーバーラップしている場合)、これで問題ありません。memcpy の仕様ではオーバーラップが許可されていないにもかかわらず、コンパイラが memcpy の呼び出しを挿入することがあるのはまだ奇妙に思えます。おそらく、コンパイラーは、ドキュメントが見逃しているよりも、 memcpy の特定の実装についてより多くのことを知っています..

于 2011-01-19T13:18:42.543 に答える