[英]Is std::memcpy between different trivially copyable types undefined behavior?
[英]Does memcpy preserve data between different types?
如果緩沖區大小足夠,在兩個不同的結構上調用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 ++編譯它。
除了推遲到C標准之外,C ++標准沒有指定memcpy
的行為。 (也許是為了避免解決這樣的問題!)。 在C標准中,它被定義為等同於一系列字符類型副本1 。
因此處理memcpy(&obj, &tmp, sizeof(tmp));
似乎是合理的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 ++標准來覆蓋該代碼。
現在的問題是:
&tmp
, &obj
實際上是否給出了對象開頭的地址? obj
填充字節怎么樣? tmp
未初始化的填充字節怎么樣? obj
的子對象的值會發生什么變化? 問題1:是的,這由[class.mem] / 19涵蓋,因為沒有基類子對象(並且它不會重載operator&
)。
問題2:我找不到任何具體涉及此事的文字; 但是,如果不允許寫入填充字節,則將類型對象復制到char緩沖區並返回到對象的標准中的示例將不起作用。
問題3:在[dcl.init] / 12中有一些文本明確允許將上述代碼用於未初始化的數據; 目的地將包含不確定的值。 因此,如果源中未初始化的填充字節僅映射到目標中未初始化的填充字節,那就沒問題。 但是如果它們映射到目標中的子對象,那么這些對象將具有不確定的值。
問題4:這里沒有問題,嚴格別名規則允許對象通過字符類型表達式覆蓋其中一些(或全部)字節。 稍后訪問該對象將產生對應於該表示的值,如果它不表示值,則使用UB。
所以,總而言之,我認為你的具體例子是可以的,假設sizeof(A) >= sizeof(B)
。
1在C中,memcpy還保留了對象的有效類型 。 C ++有一個不同的對象模型,沒有相應的。 因此,如果您使用與C編譯器類似的代碼,則還需要遵守兩個對象中類型之間的嚴格別名規則。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.