What is the best or conventional method to align members inside a structure? Is adding dummy arrays the best solution?
I have a struct of double
and a triple of double
s?
struct particle{
double mass;
std::tuple<double, double, double> position;
}
If I have an array of these, the memory will look like this
[d][d d d][d][d d d][d][d d d]...
The problem is that the distance from the first triple to the second triple is not an integer multiple of sizeof(std::tuple<double, double,double>)==3*sizeof(double)
, therefore I cannot interpret the interleaved array of triples as an array with strides.
In other words, given an array of particles particle ps[100]
, I can to take the address of a member to the first element triple* v1P = &(ps[0].position)
and I want that v1P + n == &(ps[1].position)
for some (integer) n
(that I can deduce at compile-time, for example n = sizeof(particle)/sizeof(tripe)
if sizeof(particle)%sizeof(tripe)==0
.)
What is the best method to force the triple to have a different offset?
I could stick a number of artificial double
s in the middle to match the offset:
struct particle{
double mass;
double garbage[2];
std::tuple<double, double, double> position;
}
So memory will look like this
[d][* *][d d d][d][* *][d d d][d][* *][d d d]...
but then I cannot use initializers (particle{1.,{1.,2.,3.}}
).
I could also add it to the end
struct particle{
double mass;
std::tuple<double, double, double> position;
double garbage[2];
}
So, I can keep using the initializer. Is this the best method? But it will only work in this simple case.
Another alternative could be to force alignment of the struct
to some multiple of the 3*sizeof(double)
struct alignas(3*sizeof(double)) particle{double mass; std::tuple<...> position;};
but the problem is that it is not a power of 2, so GCC and clang reject it. Note that in other sizes of the tuple the alignas
strategy works because it can solve the problem being accidentally a power of two.
For example in
struct alignas(4*sizeof(double)) particle{double mass; std::pair<double, double> position;};
alignas
gives an easy solution for this other use case (in GCC).
Is there a general or accepted solution for this?
I also found about ((packed)), is that also necessary in this solution?
I found this old article https://www.embedded.com/design/prototyping-and-development/4008281/2/Padding-and-rearranging-structure-members , https://web.archive.org/web/20190101225513/http://www.drdobbs.com/cpp/padding-and-rearranging-structure-member/240007649 .
It seems that adding arrays in the middle of was a solution back then at least. Moreover, I could use char[N]
to have finer control, to the level of a byte in this way.
double
instead of astd::tuple
. And you can still use strides, but you have to include the full size of the structures to calculate array offsets. – Arthritisparticles
also as a strided array ofpositions
(with the normal pointer arithmetic for both). 2) Nevermind the "two" values, that was a mistake, the example is more interstring with triples. 3) Yes, I understand that the solutions will be compiler dependent, I will have to adjust the offsets for different compilers, fortunately I can have compile-time assertions to detect this problem during compilation. For examplestatic_assert( sizeof(particle)%sizeof(triple) == 0 )
. – Round((packed))
to force everything on defined strides and your code probably works without problems, but I still think it is undefined behavior in c++. – Zipparticle ps[100]
, I can take the address of a member to the first elementtriple* v1P = &(ps[0].position)
. Now, the only thing I want is thatv1P + n = &(ps[1].position)
for some (integer)n
. – Roundparticle
is array represent different data, accessing directly in this way should be undefined behavior. I may be wrong though. – Zip