我有以下看似无害的代码:
void myFunc(){
struct stance {
long double interval;
QString name;
};
// [...]
}
当我在 Ubuntu 18.04 上使用标准版本的 gcc 构建它时,我收到这样的警告:
MySource.cpp:12: 警告:'stance' 的填充大小为 8 个字节 对齐边界(-wpadded)
我知道出现此警告是因为编译器需要将我的结构的填充调整为我可能没有预料到的东西,并且非常友好地警告我作为用户。
但是,我正在尝试进行无警告构建,所以问题是,如何以符合标准的方式在我的代码中明确表示编译器不需要发出此警告?
明确地说,我不想在我的构建脚本中禁止警告,也不想使用#pragma 或类似的。我想更改此结构的代码,以便我的对齐期望是明确的并匹配编译器想要做的任何事情,因此不需要显示警告。
只需禁用警告(或者 - 好吧,不要启用它,我不知道包含它的任何警告集,如
-Wall
或 -Wextra
)。 -Wpadded
并不意味着总是启用,除非您希望始终手动明确指定必要的填充。
-Wpadded
如果结构中包含填充,则发出警告,以对齐结构的元素或对齐整个结构。 有时发生这种情况时,可以重新排列结构的字段以减少填充,从而使结构更小。
(强调)
这是不可能的一种情况。
long double
为10字节,需要16字节对齐(x86 Linux上为4); QString
实际上是一个指针,因此它需要 8 字节对齐(在 32 位 Linux 上为 4)。您可以根据需要交换它们,但如果您想保持自然对齐(从而获得最佳性能),您将获得 6 + 8 字节的填充或 8 + 6 字节的填充。
总的来说,加padding不是问题,一直都在发生,有些情况是不可避免的。将它保持在最低限度的一般规则是按照对齐要求递减的顺序放置元素,但同样,它不能总是避免。
如上所述,唯一的选择(保持良好对齐)是使填充显式,但这没有多大意义(除非你正在设计文件格式或其他东西并且你想让一切都显式,但在那种情况下你不会使用
QString
并且会打包到 1 个字节)。
struct stance {
long double interval;
char unused0[6];
QString name;
char unused1[8];
};
我建议使用显式填充:
// # and ## are applied after macro substitution, but before the resulting text
// has been re-parsed for macro invocations. We add a layer of indirection to
// ensure macro arguments that are themselves macros get expanded before the
// stringizing/concatenation transformations are applied by the preprocessor.
#define CONCATENATE_(a, b) a##b
#define CONCATENATE(a, b) CONCATENATE_(a, b)
// Rather than disable warning C4324 (MSVC) or -Wpadding (GCC),
// we declare explicit padding where necessary.
#define EXPLICIT_PADDING_BYTES(N) char CONCATENATE(PADDING_MACRO__, __COUNTER__)[N]
struct alignas(4) S
{
char c;
EXPLICIT_PADDING_BYTES(3);
};