Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to reinterpret_cast an array to a struct containing the array?

Let's say I have an array of doubles, is it safe to reinterpret_cast it to an array of structs each containing 4 doubles, with regards to alignment?

Consider this example code:

double *edges = ...; // Each edge is defined by 4 doubles in the array.

struct Edge { double vals[4]; };
Edge *asStruct = reinterpret_cast<Edge*>(edges);

std::sort(asStruct, asStruct + edgesCount, EdgeLengthComparator());

Is it guaranteed by the standard that sizeof(Edge) == sizeof(double)*4 always be true and if not, is it true in practice for Intel and ARM?

Edit: I found there is an __attribute__((__packed__)) for GCC, would that guarantee it for GCC at least and does MSVC have a similar option?

like image 470
sashoalm Avatar asked Dec 23 '14 07:12

sashoalm


People also ask

Is Reinterpret_cast safe?

The result of a reinterpret_cast cannot safely be used for anything other than being cast back to its original type. Other uses are, at best, nonportable. The reinterpret_cast operator cannot cast away the const , volatile , or __unaligned attributes.

Is it possible to have a struct with arrays?

A structure may contain elements of different data types – int, char, float, double, etc. It may also contain an array as its member. Such an array is called an array within a structure. An array within a structure is a member of the structure and can be accessed just as we access other elements of the structure.

What is the point of Reinterpret_cast?

reinterpret_cast is a type of casting operator used in C++. It is used to convert a pointer of some data type into a pointer of another data type, even if the data types before and after conversion are different. It does not check if the pointer type and data pointed by the pointer is same or not.


2 Answers

Is it guaranteed by the standard?

Formally, no; in practice, yes. The closest to a guarantee is C++11 9.2/20:

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note ]

So the cast will correctly reinterpret the first array elements as a single structure; but I don't think there's a formal guarantee that it won't expect extra padding between structures.

If not, is it true in practice for Intel, AMD, and ARM?

At least on mainstream architectures like the ones you list, there's no need to add padding for alignment in this case, and no other reason to do so; so in practice, this should work, but without guaranteed portability.

I found there is an __attribute__((__packed__)) for GCC, would that guarantee it for GCC at least?

Yes. According to the documentation, this "specifie[s] that the minimum required memory be used to represent the type", so it will prevent any padding being added after the array member.

Does MSVC have a similar option?

It has a compiler flag /Zp1 and a pragma #pragma pack(push, 1) (with #pragma pack(pop) to restore default alignment), but they don't seem to offer the guarantee you need; they control the alignment of "each structure member after the first is stored", with no mention of the overall structure size.

like image 192
Mike Seymour Avatar answered Oct 15 '22 06:10

Mike Seymour


The C Standard does not guarantee this. In fact, it explicitly says (in 6.7.2.1):

There may be unnamed padding at the end of a structure or union

However, in practice, you can use implementation-specific features to force zero padding for the struct. If you do so, I recommend utilizing a static assertion technique to ensure sizeof(Edge) == sizeof(double)*4 when the code is being compiled.

Update (re C++):

A series of comments asked if I can verify this for C++. In the draft copy of C++11, page 220, it says the following (emphasis mine):

  1. A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note ]
like image 32
mmx Avatar answered Oct 15 '22 07:10

mmx