0

Can I use memcpy to copy data of one data type to another data type...

let's say I have char buffer[1024], now I want to copy my struct abc x; of size 306 (for example) into buffer..

So Is this legal/possible use without any unexpected behavior?

memcpy(buffer, &x, sizeof(x));

Then there would be any unexpected behavior if I copy back that data to struct abc y;?

memcpy(&y, &buffer, sizeof(struct abc));

and also if I have struct abc *z,

z = (struct abc *) buffer;

I try to extract struc abc from buffer.

I tried my best to explain myself please ignore or suggest if you observe any mistake...

Jarvis__-_-__
  • 287
  • 1
  • 13
  • No. You should do `memcpy(buffer, &x, sizeof(x));`. – MikeCAT Jun 17 '21 at 18:41
  • @MikeCAT yeah, sorry that was my typo.. now edited .. – Jarvis__-_-__ Jun 17 '21 at 18:42
  • It is "legal" in the sense that you can do it; just what the 2 datatypes are will have some influence on the expectedness of the resulting behavior. – Scott Hunter Jun 17 '21 at 18:44
  • @ScottHunter That's what I am curious about. – Jarvis__-_-__ Jun 17 '21 at 18:46
  • That's a pretty broad question; care to narrow it down a bit? For example, if you copied your struct to a buffer, and then from that buffer to another instance of that struct, you'd be fine. – Scott Hunter Jun 17 '21 at 18:48
  • @ScottHunter You can tell me a scenario where buffer data is again copied to ```y``` . – Jarvis__-_-__ Jun 17 '21 at 18:53
  • I have no idea what that sentence means; for starters, what is `y`? – Scott Hunter Jun 17 '21 at 18:55
  • 1
    If you have different structures to copy to/from a buffer, your program should also know what structure was copied to the buffer. There is no help from the compiler to prevent you from copying a `struct abc` to the buffer and later copy data from the buffer to a `struct def` which might produce unexpected results. And when you copy the data from the buffer to system that uses a different OS/processor/compiler, the same structure in source code might not be compatible to the data in the buffer. – Bodo Jun 17 '21 at 18:55
  • please find the edit , I tried another example. – Jarvis__-_-__ Jun 17 '21 at 18:58
  • 1
    " Is this legal/possible use without any unexpected behavior?" --> in the by gone era of non 2's compliment, forming a `char` with a trap value was a risk. Even today, best to for the copy buffer to be `unsigned char` rather than `char` to mitigate subsequent buffer uses. – chux - Reinstate Monica Jun 17 '21 at 18:58
  • 1
    Jarvis__-_-__: `void buffer[size];` is not standard C. Best to post true compliable code. – chux - Reinstate Monica Jun 17 '21 at 18:59
  • wait guys let me edit again. – Jarvis__-_-__ Jun 17 '21 at 19:01
  • now please find the edit.. – Jarvis__-_-__ Jun 17 '21 at 19:04
  • I'm having a hard time understanding your question. As some people already said, yes it is indeed legal. About the undefined behaviour. Well, it is pretty safe to say that sizeof(x) == sizeof(y) == sizeof(struct abc). So you should be fine. Anyway that's kind of counterintuitive. – Tretorn Jun 17 '21 at 21:44
  • Re the `z = (struct abc *) buffer;` example: The C standard **does not** guarantee that it will work. Within a specific system it will (nearly always) work but if you are strict about complying to the standard the don't do such stuff. – Support Ukraine Jun 19 '21 at 07:34

3 Answers3

0

Other answers have already addressed the memcpy part. And yes, it's fine to use memcpy to copy an object of type T into a char buffer and later use memcpy to copy the data from the char buffer back to an object of type T. No problem.

In this answer I'll address the last part of the question, i.e. is it okay to do:

memcpy(buffer, &x, sizeof(x));
z = (struct abc *) buffer;

The answer is: No, it's not safe according to the C standard

One issue is that the buffer isn't guaranteed to preserve the alignment requirements of the struct members.

On modern systems (at least all modern systems, I know) it will work just fine but if you want to be strict about complying to the C standard, you shouldn't do such things.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
-2

This:

char buffer[1024];
struct abc x;
// Init x
memcpy(buffer, &x, sizeof(x));
struct abc y;
memcpy(&y, buffer, sizeof(y));

will ensure that if you have a function T foo(struct abc arg) where T could be any type, then T a = foo(x); and T a = foo(y); will behave the same. Except if sizeof(struct abc) is larger than the buffer.

However, if you do this:

puts(buffer);

It's not guaranteed to give the same printout. This means that if you write the buffer to a file or send it via network to another machine, then a program running on another machine may be unable to read it properly.

klutt
  • 30,332
  • 17
  • 55
  • 95
-2

memcpy way is correct and it will not invoke Undefined Behaviour. Most modern compilers know how the memcpy function works and in many circumstances they will not call it.

Example:

struct abc
{
    int a,b,c;
    double d,e,f;
}x;

void foo(void *ptr)
{
    memcpy(&x, ptr, sizeof(x));
}

foo:
        movdqu  xmm0, XMMWORD PTR [rdi]
        movaps  XMMWORD PTR x[rip], xmm0
        movdqu  xmm1, XMMWORD PTR [rdi+16]
        movaps  XMMWORD PTR x[rip+16], xmm1
        mov     rax, QWORD PTR [rdi+32]
        mov     QWORD PTR x[rip+32], rax
        ret

Pointer punning is not safe and you should not use it (if you want to know why - read about strict aliasing rule What is the strict aliasing rule?).

0___________
  • 60,014
  • 4
  • 34
  • 74