Does memcpy save data between different types?

Does calling memcpy on two different structures support raw data if the buffer size is sufficient? And is it defined to get values ​​of another data type with data from the previous data type, if their respective data types overlap?

This should be similar for both c / cpp languages, but I provide an example in 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"; } 

In the above example, I commented on the 1st and 2nd comments, are they valid and data is saved if there is a sufficient buffer area? Can we make it portable?

The structure and other related functions are in the C library, but we will use and compile it using C ++.

+3
source share
1 answer

The C ++ standard does not specify memcpy behavior other than deferring to standard C. (Perhaps to avoid such problems!). In the C standard, it is defined as the equivalent of a sequence of copies of character type 1 .

Therefore, it seems reasonable to consider memcpy(&obj, &tmp, sizeof(tmp)); as:

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

and then use C ++ Standard to cover this code.

Now there are problems:

  • Does &tmp , &obj address of the beginning of the object?
  • How about filling bytes in obj ?
  • What about uninitialized fill bytes in tmp ?
  • What happens to obj sub-object values?

Problem 1: Yes, this applies to [class.mem] / 19, since there are no subobjects of the base class (and it does not overload operator& ).

Problem 2: I cannot find text specifically covering this; but an example in the standard for copying a class object to the char buffer and back to the object will not work if it was not allowed to write fill bytes.

Problem 3: There is text in [dcl.init] / 12 that explicitly allows the use of the above code for uninitialized data; and the destination will contain undefined values. Therefore, if uninitialized padding bytes in the source are only mapped to uninitialized padding bytes at the destination, this is good. But if they are mapped to sub-objects at the destination, then these objects will have an undefined value.

Problem 4: there are no problems, the strict rule of aliases allows objects to have some (or all) of their bytes, rewritten by an expression of the symbol type. After that, access to the object will give the value corresponding to the view, with UB if it does not represent the value.

So, overall, I think your specific example is fine, assuming sizeof(A) >= sizeof(B) .


1 In C, memcpy also maintains an efficient object type. C ++ has another object model, and there is no equivalent. Therefore, if you used the same code with the C compiler, you would also need to follow the strict rule of aliases between types in both objects.

+4
source

Source: https://habr.com/ru/post/1264419/


All Articles