0

Is direct assignment (i.e. =) the same as casting something to char* and then using a for loop to copy it byte after byte?*
I want to know if there's an advantage of one method over the other.

struct A
{
    int a;
    int b;
} Test;

void* Buffer = malloc(1024);


// Casting and byte copying
for (int i=0; i != 8; i++)
{
    ((char*)Buffer)[i] = ((char*)Test)[i];
}

// Assignment
((A*)Buffer)[0] = Test;

* all types are bitwise copyable.

EDIT: based on answers, is memcopy the same as '='

Eitan T
  • 32,660
  • 14
  • 72
  • 109
Lauer
  • 517
  • 1
  • 6
  • 11

4 Answers4

10

This is basically what memcpy does, and is valid for POD types (assuming sizeof(Test) really is 8). However, memcpy will almost certainly be faster, because the compiler will have special optimised assembler routines.

You'll invoke undefined behaviour if you try this (or memcpy) with a non-POD type. So in general, you should use std::copy or just use assignment.

You should also avoid malloc in C++, because it's not type-safe; use new, or placement new if you have to.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • everyting going into the buffer is either POD or an array of POD. – Lauer Jun 27 '12 at 14:39
  • 1
    @user1204406: Then the manual copying is safe. But it's also pointless, probably slower, and harder to read/maintain than a simple `=`. – Oliver Charlesworth Jun 27 '12 at 14:44
  • theres a time when i need to spread one object over 2 buffers. so manual copying is nessacary. but sometimes it only goes into one buffer so '=' works there. should i make a special case for if i can fit it or just stick with the for loop to be consistant? – Lauer Jun 27 '12 at 14:48
  • 1
    @OliCharlesworth "However, `memcpy` will almost certainly be faster"---I'd expect just the opposite. `memcpy` is generic; it has to handle all possible situations. If you write the loop (or use `std::copy`), the compiler can see the exact conditions, and optimize accordingly. – James Kanze Jun 27 '12 at 15:04
  • @JamesKanze: I'm comparing `memcpy` to the manual for loop. My understanding is that most compilers have a `memcpy` intrinsic, although this is not something I've ever dug into. – Oliver Charlesworth Jun 27 '12 at 15:06
  • @JamesKanze: all semi-decent compilers have a `memcpy` intrinsic and are able to turn a copy loop into `memcpy` and vice-versa. –  Jun 27 '12 at 15:10
  • @user1204406: I would still be tempted to use `memcpy` rather than a manual loop. – Oliver Charlesworth Jun 27 '12 at 15:53
  • @OliCharlesworth A lot of C compilers might have a `memcpy` intrinsic, but C++ is a different kettle of fish. The usual technique for implementing the intrinsic (a special macro) isn't legal in C++, and because the function is so dangerous, it's rarely used in C++, so why should a compiler vendor invest the effort to develop a new technique? – James Kanze Jun 27 '12 at 16:44
  • @OliCharlesworth I would never use `memcpy` in C++, because it rarely works---very, very few data types are POD. And there's `std::copy`, which does the job correctly. (I wouldn't hand write such a loop either.) – James Kanze Jun 27 '12 at 16:45
  • @user1204406 If you're marshalling for transmission, none of the solutions mentioned so far work. – James Kanze Jun 27 '12 at 16:47
1

First of all, this is not C++. This is ugly C. You're manually allocating a block of memory the size of 1024 bytes, capturing its address in a naked pointer. Also, in the code sample, you never free any of it, leaking a MB of memory. This is considered an extremely bad practice when it comes to C++.

C++ is not C with classes, it's a beautiful language that can only express itself by using it in combination with the standard library and adhering to better design patterns which come naturally with OO programming, especially with the notions of RAII, general encapsulation which can result in better memory management. Even new is evaded when unnecessary, let alone malloc.

for (int i=0; i != 8; i++)

Also, you're making dangerous assumptions here which can lead to undefined behavior.

((char*)Buffer)[i] = ((char*)Test)[i];

I am not even going to comment on this. Holy... Not only it's bad, it doesn't work. You're trying to force an instance of struct A lying on the stack, a regular "object"/var, into a char*. You're missing the &Test.

Use memcpy if you're taking this path, but please consider improving on your C++ approach. memcpy takes three arguments, a destination, a source and the size in bytes. Make sure the two match up and you'll get a quick per-byte copy.

  • :cant send pointers over TCP. PART of this is loading classes w/pointers into a buffer so it can be bitwise copyied. so i need a block of memory that can hold the class data and the arrays inside(dynamicaly allocated). And no, im not going to free something that will be reused, thats less efficient. – Lauer Jun 27 '12 at 15:09
0

Direct assignment, using the = operator, is definitely not the same as a for loop copying the bytes. The = operator respects the type, and what it does will depend on the type. And copying byte by byte is undefined behavior in most cases. In your particular case, I would expect that the compiler generate something equivalent to treating the data as an unsigned long long, and copying that, with just one or two machine instructions. But that's only because of the particularities of the type you defined. In general, give the compiler as much information as you can, and trust it; it will usually do a better job that you can.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • read Oli's answer and comments, there are two buffers so i need to break the struct into smaller types. – Lauer Jun 27 '12 at 15:11
0

This is not a direct answer to OP's question but instead, it is an answer to what I think he is trying to achieve.

Writing formatted data to a transferable format is serialization and in C++, there are several ways to do this. There are several things to consider: should the format be ascii, xml, binary and in case of binary, should it be crossplatform (endianess, alignment). In any case, the naive way of copying structs to a byte buffer is almost never desirable.

You can consider following options:

  • when it may be in ascii format, the most straightforward way is to use iostreams
  • boost.serialization
  • external libraries (fair enough: boost is also one): poco, google buffer protocol, ...
  • rolling your own (based on converting primitives)

see also this question

Community
  • 1
  • 1
stefaanv
  • 14,072
  • 2
  • 31
  • 53
  • Hit the nail on the head. I would like write it myself though so I learn more. – Lauer Jun 27 '12 at 15:57
  • Doing it myself, is it worth making a special case to use "="? – Lauer Jun 27 '12 at 16:04
  • No, if you want to overload an operator, use operator<< to stream to your buffering stream, so it is similar to streaming to std::cout – stefaanv Jun 27 '12 at 19:51
  • No I'm not making a class. I want to copy a POD into a buffer. Should I Make a special case to use = if the POD can fit into one buffer. – Lauer Jun 28 '12 at 16:05