I have the following class,
struct employee {
std::string name;
short salary;
std::size_t age;
};
Just as an example, in Linux amd64, the size of the struct is 48 bytes, and the size of std::string is 32, that is, not a multiple.
Now, I need, in a cross-platform way, for employee
to have a size that is a multiple of the size of std::string
(first member).
(Cross-platform could mean, for example, both Linux amd64 and Apple ARM.)
That is, sizeof(employee) % sizeof(std::string) == 0
.
I tried controlling the padding using alignas
for the whole class or the members, but the requirement to be a power of 2 is too restrictive, it seems.
Then I tried to add a char
array at the end.
Still, I had two problems, first, what is the exact size of the array in different platforms at compile-time, and second not adding another member that can screw up the nice aggregate initialization of the class.
For the first, I do this:
struct employee_dummy {
std::string name;
short salary;
std::size_t age;
};
struct employee {
std::string name;
short salary;
std::size_t age;
char padding[(sizeof(employee_dummy)/sizeof(std::string)+1)*sizeof(std::string) - sizeof(employee_dummy)];
};
Note the ugly dummy class, and I don't even know if the logic is correct.
For the second problem, I don't have a solution. I could do this, but then I would need to add a constructor, the class would not be an aggregate, etc.
struct employee {
std::string name;
short salary;
std::size_t age;
private:
char padding[(sizeof(employee_dummy)/sizeof(std::string)+1)*sizeof(std::string) - sizeof(employee_dummy)];
};
How can I control the size of the struct with standard or non-standard mechanisms and keep the class as an aggregate?
Here is a link to play with this problem empirically: https://cppinsights.io/s/f2fb5239
NOTE ADDED:
I realized that, if the technique to add padding is correct, the calculation is even more difficult because the dummy class might be already adding padding, so I have to take into account the offset of the last element instead.
In this example I want data
to be a multiple of the first member (std::complex
):
struct dummy {
std::complex<double> a;
double b;
std::int64_t b2;
int c;
};
struct data {
std::complex<double> a;
double b;
std::int64_t b2;
int c;
char padding[ ((offsetof(dummy, c) + sizeof(c)) / sizeof(std::complex<double>) + 1)* sizeof(std::complex<double>) - (offsetof(dummy, c) + sizeof(c)) ];
};
Note the formula is even worse now.
sizeof(std::string)
? Is it not possible to specify the stride in bytes? – Effetechar : 8*num_padding_bytes;
. But out of the big three, MSVC rejects bitfields larger than the underlying type size. – Effetewarning #959-D: declared size for bit field is larger than the size of the bit field type; truncated to 8 bits
, clang might warn with-Wbitfield-width
. Some flags combinations (not sure) in GCC can givewidth of ‘employee::padding’ exceeds its type
. – Mathenystd::string
depends on the standard library and compiler being used? It's not just "amd64 linux", it's "amd64 linux with libstdc++ in debug mode" – Illfoundeddata
) for a type that is a bit less dependent on the environment. – Mathenystatic_assert
was failing with 8 != 0, the calculations seem all right if you use aunion PaddedData { data d; char buf[padding<std::complex<double>, double, int, int64_t>()]; };
and adjust thepadding
function to return a total size rather than the remainder ie buf is48
. A union might make aggregate arguments harder but it means that you can separate your struct with important data from the less important padding. – Sleekitshort salary;
andstd::size_t age;
tells you something about life, world, society, economy and all that stuff. Yes, that’s just how things are! – Hendrik