2016-07-27 67 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

在memcpy(&s3,&s1,sizeof(s3));由於'sizeof(s1)'小於'sizeof(s3)''以外的對象範圍之外訪問的未定義行爲。 – EOF

+0

這是'結構'日還是什麼? –

回答

0
s2 = *(extended*)&s1; 

這未定義的行爲,在&s1對象不是正確類型的通過extended*類型的指針來訪問。

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

這也有不確定的行爲,因爲你讀的對象,只有sizeof(base)字節長sizeof(extended)字節。

如果你仔細想想,它顯然不會像你期望的那樣工作。當您複製extended結構時,編譯器從源讀取三個單詞(即sizeof(extended)),並將這三個單詞複製到目標。它不會複製少於三個字,並保持最後一個字不變。你告訴它從地址&s1讀取sizeof(extended)字節,這正是它所做的。並且最後一個成員被設置爲垃圾值,因爲您從不是s1的一部分的內存位置讀取它幷包含一些垃圾值。

爲什麼你期望編譯器複製sizeof(base)字節如果你告訴它複製sizeof(extended)字節?如果你不希望它複製更多的字節,那麼不要讓它複製更多的字節!

+0

我想你會想要:memcpy(&s3,&s1,sizeof(base));而不是:memcpy(&s3,&s1,sizeof(extended)); ...爲了只複製前兩個字段。 –

+0

當然可以。如果你只想複製's1'的內容,那麼不要告訴它將's1'加上它後面的任何內容! –

0

,當你從一個存儲位置複製到另一個使用指針蒙上你基本上是「考慮事項到你自己的手中」

這些語句:

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

等同於這些:

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

我認爲很明顯,爲什麼從複製基地*來源擴展*目標將只覆蓋部分數據,而其他方式會產生災難性後果(您有超出內存訪問範圍並可能覆蓋重要數據)。

相關問題