Reputation: 9668
I have the following innocuous looking code:
void myFunc(){
struct stance {
long double interval;
QString name;
};
// [...]
}
When I build this using standard version of gcc on Ubuntu 18.04 I get a warning like this:
MySource.cpp:12: warning: padding size of 'stance' with 8 bytes to alignment boundary (-wpadded)
I know that this warning shows up because the compiler needs to adjust the padding for my struct to something that I might not have expected and is kind enough to warn me as the user about this.
However, I am trying to have a warning-free build and so the question is, how can I make it explicit in my code in a standard compliant way that the compiler does not need to issue this warning?
So to be clear, I don't want to suppress warnings in my build script, nor using #pragma or similar either. I want to change the code of this struct so that my alignment expectations are explicit and match whatever the compiler wants to do hence not needing the warning to be displayed.
Upvotes: 5
Views: 9050
Reputation: 736
I would recommend using explicit padding:
#include <cstdint>
#define EXPLICIT_PADDING_BITS(N) uint8_t : N;
struct stance {
long double interval;
QString name;
EXPLICIT_PADDING_BITS(8)
};
Without the padding, you'll trip -Wpadded
in GCC and Clang (as you saw), and warning C4324
in MSVC.
From the standard (§14.9.2, part 2, ISO/IEC JTC1 SC22 WG21 N4860):
A declaration for a bit-field that omits the identifier declares an unnamed bit-field. Unnamed bit-fields are not members and cannot be initialized. An unnamed bit-field shall not be declared with a cv-qualified type. [Note: An unnamed bit-field is useful for padding to conform to externally-imposed layouts. — end note] As a special case, an unnamed bit-field with a width of zero specifies alignment of the next bit-field at an allocation unit boundary. Only when declaring an unnamed bit-field may the width be zero.
If you want to pad more than 8 bits, you could use an unnamed uint16_t
, uint32_t
, or uint64_t
(but keep in mind that will make the minimum padding of the structure at least 2, 4, and 8 bytes respectively).
If you want to pad more than 8 bytes, you can't use an unnamed bit-field. You'll need to write something like this:
#include <cstdint>
// We need to add the second "CONCATENATE_" macro to ensure that the
// special "__COUNTER__" macro is expanded before it's concatenated
// to "PADDING_MACRO_".
#define CONCATENATE_(a,b) a##b
#define CONCATENATE(a,b) CONCATENATE_(a,b)
#define EXPLICIT_PADDING_BYTES(N) uint8_t CONCATENATE(PADDING_MACRO_, __COUNTER__)[N];
// Suppose we want to avoid false-sharing, so we make sure that
// our structure occupies its own entire 64-byte cache line:
struct alignas(64) example {
uint64_t atomic_counter;
EXPLICIT_PADDING_BYTES(56);
};
Upvotes: 2
Reputation: 126787
Just disable the warning (or - well, don't enable it, I don't know of any warning set like -Wall
or -Wextra
that includes it). -Wpadded
is not meant to be always enabled, unless you want to always manually specify the necessary padding explicitly.
-Wpadded
Warn if padding is included in a structure, either to align an element of the structure or to align the whole structure. Sometimes when this happens it is possible to rearrange the fields of the structure to reduce the padding and so make the structure smaller.
(emphasis added)
This is one case where it's not possible. long double
is 10 bytes, and it requires 16 bytes alignment (4 on x86 Linux); QString
is effectively a pointer, so it needs 8 bytes alignment (4 on 32 bit Linux). You can swap them however you want, but if you want to keep natural alignment (and thus best performance) you'll either get 6 + 8 bytes of padding or 8 + 6 bytes of padding.
In general, adding padding is not a problem, happens all the time and there are cases such as this when it's unavoidable. The general rule to keep it at a minimum is to place elements in order of decreasing alignment requirements, but again, it cannot always be avoided.
As mentioned above, the only alternative (keeping good alignment) is making the padding explicit, but it doesn't make much sense (unless you are designing a file format or something and you want to make everything explicit, but in that case you wouldn't use a QString
and would pack to 1 byte).
struct stance {
long double interval;
char unused0[6];
QString name;
char unused1[8];
};
Upvotes: 7
Reputation: 1
I want to change the code of this struct so that my alignment expectations are explicit
It looks like you want the alignof
operator and use it with alignas
specifier. So you need at least C++11 and you might want std::alignment_of
Upvotes: 0