2017-02-19 92 views
4

如果緩衝區大小足夠,在兩種不同結構上調用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'既不知道也不關心數據類型。它複製您指定的字節數,無論目標緩衝區是否足夠大。當範圍重疊時,行爲是* undefined *,應該使用'memmove'。 –

+1

'memcpy()'不能保證任何關於底層數據類型。 –

+3

C或C++?這些是兩種不同的語言,具有完全不同的對象模型。 –

回答

3

C++標準沒有規定memcpy的行爲,除了推遲到C標準。 (也許要避免解決這樣的問題!)。在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:是的,由於沒有基類子對象(並且它沒有超載operator&),所以它覆蓋了[class.mem]/19。

問題2:我找不到任何具體的文字;但是如果不允許寫入填充字節,則將類型對象複製到char緩衝區並返回到對象中的示例不起作用。

問題3:在[dcl.init]/12中有一些文本明確允許將上述代碼用於未初始化的數據;目的地將包含不確定的值。因此,如果源中未初始化的填充字節僅映射到目標中未初始化的填充字節,則沒問題。但是,如果它們映射到目標中的子對象,那麼這些對象將具有不確定的值。

問題4:這裏沒有問題,嚴格的別名規則允許對象通過字符類型表達式覆蓋部分(或全部)字節。稍後訪問對象將產生與表示相對應的值,如果UB不表示值,則返回UB。

所以,總而言之,我認爲你的具體例子是好的,假設sizeof(A) >= sizeof(B)


在C中,MEMCPY還保留了對象的有效類型的。 C++有一個不同的對象模型,並沒有相應的對象模型。因此,如果您在C編譯器中使用了類似的代碼,您還需要遵守兩個對象中類型之間嚴格的別名規則。

+1

關於第三點,這也應該支持你的論點 - http://en.cppreference.com/w/cpp/language/data_members#Standard_layout,對吧? –

+0

@AbhinavGauniyal是的,我會修改答案 –

+0

@ M.M如果我調用'memcpy()之前的'memset(..,0,..)'所有結構'這應該解決未初始化位的問題? – buggy3

相關問題