2
struct Point
{
    double X;
    double Y;
};

Q1) is the following portable (compilers / machines)

Point point = { 1.1, 2.2 };
double arr[2] = {};
memcpy(arr, point, sizeof(double)*2);

Q2) same for array of struct

Point *pPoints = new Point[numPoints];
double *pArr = new double[2*numPoints];
memcpy(pArr, pPoints, sizeof(double)*2*numPoints);

on Windows/MSVC I'm expecting both to succeed.

EDIT: I'm not asking these questions for every possible structs/classes; I'm asking for this particular case of struct "Point" (notice : only 2 pods, no virtualmember / user constructor/user desctructor). This might as well be a C question it has to do with struct alignment and memory layout accross compilers.

So far I've got that the c/c++ standard doesn't enforce anything for the layout of Point so I must ensure it myself with a static assert, correct ?

user1968335
  • 276
  • 2
  • 8
  • 1
    possible duplicate of [C++ memcpy() vs std::copy()](http://stackoverflow.com/questions/4707012/c-memcpy-vs-stdcopy) – trojanfoe Jul 01 '13 at 10:33
  • @trojanfoe: How do you see that? This is about structure vs. array layout, not the performance of memcpy... – Mats Petersson Jul 01 '13 at 10:37
  • @trojanfoe I see no reason to think this question is a dup of the one you linked, not in the slightest. – mah Jul 01 '13 at 10:37

4 Answers4

8

Your code makes the assumption that sizeof(struct Point) == 2*sizeof(double);. This is a dangerous assumption because it will be true when you write and test the code but it's true by luck, not be definition. Luck has a habit of running out :)

Most likely in this case you'll never have a problem (since the definition of struct Point is unlikely to ever change, and machine alignment issues aren't likely in portability with this type either). That being said, it's a horrible pattern to base code on.

mah
  • 39,056
  • 9
  • 76
  • 93
  • so, and what's the story if static_assert(sizeof(Point) == 2* sizeof(double), "try harder with packing") inserted at the point? – Balog Pal Jul 01 '13 at 10:53
  • @BalogPal yes, you can make checks to ensure that your requirements hold true. I wouldn't suggest it without a good reason since it adds maintenance complexity for potentially someone else needing to maintain your code in a year. Sometimes this isn't avoidable, but if it can be reasonably avoided, I would avoid it. – mah Jul 01 '13 at 10:55
  • You talk about luck and fear -- check handles that part. To me this case sounds laughable as "maintenance complexity" compared to actual real life problems we encounter. – Balog Pal Jul 01 '13 at 11:01
0

In theory the struct can have padding between members and after the end. So it is not necessarily layout-compatible with plain doubles. But if you add 0 packing and static_assert to ensure sizeof(Point) == 2* sizeof(double) I don't see a way to fail in practice.

Balog Pal
  • 16,195
  • 2
  • 23
  • 37
0

Well, let's start with the fact I completely back what @mah said. Indeed that's terrible and should be avoided if possible.

But, sometimes, it is not possible. For example, you sometimes need to do the exactly other way around: you've received a stream of numbers which are in certain order, and you want to "unpack it" into structures for better handling. That's where strict control of memory layout is required.

In such cases, if may decorate the struct Point with proper packing directives like #pragma pack(1) that might tell your compiler to not add any align.

Please note that this is #pragma. While some may seem somewhat universal, they are by definition compiler/platform specific. Be sure to add some simple assertions that check if sizeofs are really equal in case you change the compiler or upgrade it to a version which treats pragmas differently..

Assuming your compiler have understood the pack(1) pragmas (or similar), your code will be safe and sizeof such POD struct will indeed equal to 2*double. See nice example here https://stackoverflow.com/a/3318475/717732

I actually do not remember about packing in arrays. I am almost sure that an array is guaranteed to be packed with zero align. But, only almost sure. Best check the STD.

Community
  • 1
  • 1
quetzalcoatl
  • 32,194
  • 8
  • 68
  • 107
0

I want to add something to the answers of mah & quetzacoatl - which are both valid and correct.

  1. write the code in a way that it does not depend on undefined things. Here, your code probably works - because double are 8 byte aligned and normally packed. Still this is implicit. You should make sure it works always by using the sizeof the POD.
  2. If you require the pod to be packed, make it explicit by adding the pragma pack or something similar. It declares your requirement in code.
  3. Make sure the code fails if it does not meet your requirement. Use static_assert if possible, if not possible work with asserts, error handling code and/or unit tests.

In your example - add pragma if packing is a requirement and make sure that the copy does not fail even if the compiler creates a different layout than you expect. Make sure that compiling fails in case the compiler wants to create a different layout than required.

Tobias Langner
  • 10,634
  • 6
  • 46
  • 76