関数の引数として C 配列を使用する従来の memcpy の落とし穴。以下で指摘したように、コードにエラーがありますが、エラーのあるコードはローカル コンテキストで機能しました。
オブジェクトを使用して Macintosh の画像オペコードの再生をエミュレートしている移植作業で、この奇妙な動作に遭遇しました。私の DrawString オブジェクトは、明らかに文字列引数のコピーに失敗したため、再生時にガベージを描画していました。以下は私が書いたテストケースです - 手動コピーループがどのように機能するかに注意してください。しかし、memcpy は失敗します。Visual Studio デバッガーでトレースすると、memcpy が宛先をガベージで上書きすることが示されます。
2 つのローカル Str255 配列の Memcpy は正常に動作します。
それらの 1 つがスタック上のオブジェクトのメンバーである場合、失敗します (他のテストでは、オブジェクトがヒープ上にある場合にも失敗します)。
次のサンプル コードは、memcpy が operator= で呼び出されることを示しています。コンストラクターで失敗した後、そこに移動しましたが、違いはありませんでした。
typedef unsigned char Str255[257];
// snippet that works fine with two local vars
Str255 Blah("\004Blah");
Str255 dest;
memcpy(&dest, &Blah, sizeof(Str255)); // THIS WORKS - WHY HERE AND NOT IN THE OBJECT?
/*!
class to help test CanCopyStr255AsMember
*/
class HasMemberStr255 {
public:
HasMemberStr255()
{
mStr255[0] = 0;
}
HasMemberStr255(const Str255 s)
{
for (int i = 0; i<257; ++i)
{
mStr255[i] = s[i];
if (s[i]==0)
return;
}
}
/// fails
void operator=(const Str255 s) {
memcpy(&mStr255, &s, sizeof(Str255));
};
operator const Str255&() { return mStr255; }
private:
Str255 mStr255;
};
-
/*!
Test trivial copying technique to duplicate a string
Added this variant using an object because of an apparent Visual C++ bug.
*/
void TestMacTypes::CanCopyStr255AsMember()
{
Str255 initBlah("\004Blah");
HasMemberStr255 blahObj(initBlah);
// using the operator= which does a memcpy fails blahObj = initBlah;
const Str255& dest = blahObj; // invoke cast operator to get private back out
CPPUNIT_ASSERT( dest[0]=='\004' );
CPPUNIT_ASSERT( dest[1]=='B' );
CPPUNIT_ASSERT( dest[2]=='l' );
CPPUNIT_ASSERT( dest[3]=='a' );
CPPUNIT_ASSERT( dest[4]=='h' );
CPPUNIT_ASSERT( dest[5]=='\0' ); // trailing null
}