2017-02-19 3 views
4

バッファサイズが十分である場合、2つの異なる構造のmemcpyを呼び出して元のデータを保持しますか?また、それぞれのデータ型が重複していれば、以前のデータ型のデータを持つ別のデータ型の値を取得するように定義されていますか?memcpyは異なるタイプ間でデータを保存しますか?

これは、C/CPPの両方の言語についても同様でなければなりませんが、私は、CPPの例を提供しています -

#include <iostream> 
#include <cstring> 

using namespace std; 

struct A{ 
    int a; 
    char b[10]; 
}; 

struct B{ 
    int ba; 
    int bb; 
}; 

int main(){ 
    B tmp; 
    tmp.ba = 50; 
    tmp.bb = 24; 
    cout << tmp.ba << tmp.bb << "\n"; 

    // everything is fine yet 

    A obj; 
    memcpy(&obj, &tmp, sizeof(tmp)); 

    // 1. is this valid? 
    cout << obj.a << "\n"; 

    B newB; 
    memcpy(&newB, &obj, sizeof(newB)); 

    // 2. Are these valid? 
    cout << newB.ba << newB.bb << "\n"; 
} 

上記の例では、私が第一にコメントして第二のコメント、彼らは有効であり、データが保存されてきました十分なバッファ領域があれば?私たちはこれを移植可能なことができますか?

それに関連する構造体やその他の関数はCライブラリにありますが、これを使用してC++でコンパイルします。

+4

'memcpy'はデータ型を知らず、気にもしません。宛先バッファが十分に大きいかどうかにかかわらず、指定したバイト数がコピーされます。範囲が重なると、振る舞いは*未定義*であり、 'memmove'を使うべきです。 –

+1

'memcpy()'は基礎となるデータ型に関する何も保証しません。 –

+3

CまたはC++?それらは全く異なるオブジェクトモデルを持つ2つの異なる言語です。 –

答えて

3

C++標準では、C標準を延期する以外に、memcpyの動作が指定されていません。 (おそらく、このような問題に取り組むのを避けるために)! C標準では、文字型コピーのシーケンスと同等であると定義されています。

だから、としてmemcpy(&obj, &tmp, sizeof(tmp));を治療するための合理的なようだ:

unsigned char *dst = (char *)&obj; 
unsigned char *src = (char *)&tmp; 
for (size_t i = 0; i != sizeof tmp; ++i) 
    dst[i] = src[i]; 

し、そのコードをカバーするためにC++標準を使用しています。

問題は次のようになります。

  1. &tmp&objは、実際にオブジェクトの先頭のアドレスを与えていますか?
  2. objのパディングバイトはどうですか?
  3. tmpの初期化されていない埋め込みバイトはどうなりますか?
  4. objのサブオブジェクトの値はどうなりますか?

問題1:NO基本クラスのサブオブジェクトは、(それがoperator&に過負荷をかけない)が存在しないのであり、これは、[class.mem]/19で覆われています。

問題2:特にこれをカバーするテキストは見つかりません。クラス・タイプのオブジェクトをcharバッファにコピーしてオブジェクトに戻す標準の例は、パディング・バイトの書き込みが許可されていなければ機能しません。

問題3:[dcl.init]/12は、初期化されていないデータに対して上記のコードを明示的に使用できるテキストです。宛先には不確定な値が含まれます。したがって、ソース内の初期化されていないパディングバイトが、宛先の初期化されていないパディングバイトにのみマップされる場合は問題ありません。しかし、それらが宛先のサブオブジェクトにマップされている場合、それらのオブジェクトは不確定な値を持ちます。

問題4:ここでは問題はありません。厳密なエイリアシングルールでは、オブジェクトの一部(またはすべて)が文字型式で上書きされます。後でオブジェクトにアクセスすると、その表現に対応する値が得られます(UBは値を表していない場合)。

したがって、具体的な例はOKです。sizeof(A) >= sizeof(B)とすればいいと思います。Cにおいて


、memcpyのは、オブジェクトの有効タイプを保存します。 C++には異なるオブジェクトモデルがあり、これに相当するものはありません。したがって、Cコンパイラで同様のコードを使用した場合、両方のオブジェクトの型間の厳密なエイリアシング規則を遵守する必要があります。

+1

約3点目ですが、これはあなたの議論をサポートするはずです - http://en.cppreference.com/w/cpp/language/data_members#Standard_layout、右? –

+0

@AbhinavGuniyalはい、 'memcpy()'を呼び出す前にすべての構造体を 'memset(..、0、..)'すれば答えは –

+0

@MMを修正します。これは初期化されていないビットの問題を解決するはずですか? – buggy3

関連する問題