2016-07-27 7 views
-1

部分的なコピーでは、一致するフィールドをコピーで設定しますが、一致しないフィールドは設定しないままにします(つまり、以前の値を保持する)。構造体のインスタンスを、ある文の別の型の別の型に部分的にコピーできますか?

それは起こっていないようです。私はなぜ不思議です、そして、これが未定義の振る舞いであれば?

#include <stdio.h> 

#define print_base(s) printf("%d %d\n", s.a, s.b) 
#define print_extended(s) printf("%d %d %d\n", s.a, s.b, s.c) 

typedef struct 
{ 
    int a; 
    int b; 
} base; 

typedef struct 
{ 
    int a; 
    int b; 
    int c; 
} extended; 

int main() 
{ 
    base s1 = {1,2}; 
    extended s2 = {0}; 
    extended s3 = {0}; 
    extended s4 = {4,5,6}; 
    extended s5 = {4,5,6}; 
    extended s6 = {7,8,9}; 
    base s7 = {0}; 

    print_extended(s2); 
    s2 = *(extended*)&s1; 
    print_extended(s2); 

    print_extended(s3); 
    memcpy(&s3, &s1, sizeof(s3)); 
    print_extended(s3); 

    print_extended(s4); 
    s4 = *(extended*)&s1; 
    print_extended(s4); 

    print_extended(s5); 
    memcpy(&s5, &s1, sizeof(s5)); 
    print_extended(s5); 

    /* lossy copy */ 
    print_base(s7); 
    s7 = *(base*)&s6; 
    print_base(s7); 

    return 0; 
} 

/* 
Actual Expected 
0 0 0 0 0 0 
1 2 1 1 2 0 
0 0 0 0 0 0 
1 2 1 1 2 0 
4 5 6 4 5 6 
1 2 1 1 2 6 
4 5 6 4 5 6 
1 2 1 1 2 6 
0 0  0 0 
7 8  7 8 
*/ 
+2

'sizeof(s1)'が 'sizeof(s3)'より小さいので、 'memcpy(&s3、&s1、sizeof(s3));'のオブジェクトの境界を越えてアクセスするための未定義の動作です。 – EOF

+0

これは 'struct'の日か何ですか? –

答えて

0
s2 = *(extended*)&s1; 

これは動作を未定義た、&s1におけるオブジェクトは、タイプextended*のポインタを介してアクセスするための正しいタイプではありません。

memcpy(&s3, &s1, sizeof(s3)); 

あなただけsizeof(base)バイト長であるオブジェクトからsizeof(extended)バイトを読み込むので、これはまた、未定義の動作をしています。

これについて考えると、明らかに期待通りに動作しません。 extended構造体をコピーすると、コンパイラはソースから3つのワード(すなわちsizeof(extended))を読み込み、その3つのワードをデスティネーションにコピーします。それは3単語未満をコピーせず、最後の単語を変更しないままにします。あなたは&s1というアドレスからsizeof(extended)バイトを読むように言ったので、まさにその通りです。そして最後のメンバーは、s1の一部ではないメモリ位置からそれを読み取り、いくつかのゴミ値を含んでいるため、ガベージ値に設定されます。

sizeof(extended)バイトをコピーすると、なぜコンパイラはsizeof(base)バイトをコピーすると思いますか?それ以上のバイトをコピーしたくない場合は、それ以上のバイトをコピーするように伝えないでください!

+0

私はあなたが望むだろうと思います:memcpy(&s3、&s1、sizeof(base)); memcpy(&s3、&s1、sizeof(extended));ではなく、次のようになります。 ...最初の2つのフィールドのみをコピーするためです。 –

+0

はい、もちろんです。 's1'の内容だけをコピーしたい場合は、' s1'をコピーするように指示してください。 –

0

あなたは別の使用ポインタに1つのメモリ位置からコピーあなたは基本的に

これらの記述に「あなた自身の手に掲げる事項を取って」いるキャスト:

s2 = *(extended*)&s1; 
s1 = *(base*)&s2; 

はこれらと同等です:

memcpy(&s2, &s1, sizeof(extended)); 
memcpy(&s1, &s2, sizeof(base)); 

コピーする理由がわかりますベース*ソース拡張* destはデータの一部のみを上書きしますが、その逆の処理は悲惨な結果を招く可能性があります(境界外のメモリアクセスがあり、重要なデータを上書きする可能性があります)。

関連する問題