Clang 中的结构填充警告
Warning for struct padding in Clang
我创建了以下结构:
typedef struct s_fct_printf
{
char flag;
void (*fct)(void*);
} t_fct_printf;
static const t_fct_printf flags[] =
{
{ 's', my_putstr_printf },
//[...]
{ 'b', display_base_2 },
};
但是当我用 clang -Weverything 编译时,我有以下警告:
warning: padding struct 'struct s_fct_printf' with 7 bytes to
align 'fct' [-Wpadded]
我找到了以下解决方案:
typedef struct s_fct_printf
{
char flag;
void (*fct)(void*);
char pad[7];
} t_fct_printf;
但这并没有解决问题:
warning: missing field 'pad' initializer [-Wmissing-field-initializers]
{ 'b', display_base_2 },
warning: padding struct 'struct s_fct_printf' with 7 bytes to
align 'fct' [-Wpadded]
所以我试过了:
typedef struct s_fct_printf
{
char flag;
char pad[7];
void (*fct)(void*);
} t_fct_printf;
但出现以下错误:
warning: incompatible pointer to integer conversion initializing 'char'
with an expression of type 'void (void *)' [-Wint-conversion]
{ 'b', display_base_2 },
warning: suggest braces around initialization of subobject
[-Wmissing-braces]
{ 'b', display_base_2 },
warning: missing field 'fct' initializer [-Wmissing-field-initializers]
{ 'b', display_base_2 },
error: initializer element is not a compile-time constant
{ 's', my_putstr_printf },
我找到的最后一个解决方案是那个,但我读到它没有优化,因为编译器不再打包我的变量。
typedef struct __atribute__((__packed__)) s_fct_printf
{
char flag;
void (*fct)(void*);
} t_fct_printf;
有什么好的解决方法吗?
您似乎在 64 位系统上运行。 char
占用一个字节,编译器希望让函数指针从 word-64 边界开始。因此,它需要在 char
之后填充 7 个字节来对齐函数指针。
似乎编译器只是通知了你,但你没有出错。
typedef struct s_fct_printf
{
char flag;
char pad[7];
void (*fct)(void*);
} t_fct_printf;
有助于解决填充问题。但是,您必须更改初始化数组的方式。
使用
static const t_fct_printf flags[] =
{
{ 's', "", my_putstr_printf },
{ 'b', "", display_base_2 },
};
否则,编译器会尝试用 my_putstr_printf
初始化成员 pad
,这不是您想要的。
更新
您可以通过使用以下方式避免 pad
大小的硬编码数字 7
:
typedef struct s_fct_printf
{
char flag;
char pad[sizeof(void(*)(void))-1];
void (*fct)(void*);
} t_fct_printf;
感谢@WeatherVane 的建议。
我对你的问题给予了适当的考虑。我不认为添加填充字段是解决方案。它破坏了代码并引入了潜在的未来问题。
我也理解一个质量要求,即所有代码都应该在没有警告或错误的情况下编译。但是,此警告仅供参考,并未指出可能的错误。
我的建议是在警告发生的地方和接受发生的地方明确禁止显示警告。我建议(以 VC 为例):
#pragma warning(disable:4123)
// The compiler will inform that padding will insert 7 bytes after flag,
// which will be unused. This is acceptable.
typedef struct s_fct_printf
{
char flag;
void (*fct)(void*);
} t_fct_printf;
#pragma warning(enable:4123)
我希望你的编译器有类似的机制。
我创建了以下结构:
typedef struct s_fct_printf
{
char flag;
void (*fct)(void*);
} t_fct_printf;
static const t_fct_printf flags[] =
{
{ 's', my_putstr_printf },
//[...]
{ 'b', display_base_2 },
};
但是当我用 clang -Weverything 编译时,我有以下警告:
warning: padding struct 'struct s_fct_printf' with 7 bytes to
align 'fct' [-Wpadded]
我找到了以下解决方案:
typedef struct s_fct_printf
{
char flag;
void (*fct)(void*);
char pad[7];
} t_fct_printf;
但这并没有解决问题:
warning: missing field 'pad' initializer [-Wmissing-field-initializers]
{ 'b', display_base_2 },
warning: padding struct 'struct s_fct_printf' with 7 bytes to
align 'fct' [-Wpadded]
所以我试过了:
typedef struct s_fct_printf
{
char flag;
char pad[7];
void (*fct)(void*);
} t_fct_printf;
但出现以下错误:
warning: incompatible pointer to integer conversion initializing 'char'
with an expression of type 'void (void *)' [-Wint-conversion]
{ 'b', display_base_2 },
warning: suggest braces around initialization of subobject
[-Wmissing-braces]
{ 'b', display_base_2 },
warning: missing field 'fct' initializer [-Wmissing-field-initializers]
{ 'b', display_base_2 },
error: initializer element is not a compile-time constant
{ 's', my_putstr_printf },
我找到的最后一个解决方案是那个,但我读到它没有优化,因为编译器不再打包我的变量。
typedef struct __atribute__((__packed__)) s_fct_printf
{
char flag;
void (*fct)(void*);
} t_fct_printf;
有什么好的解决方法吗?
您似乎在 64 位系统上运行。 char
占用一个字节,编译器希望让函数指针从 word-64 边界开始。因此,它需要在 char
之后填充 7 个字节来对齐函数指针。
似乎编译器只是通知了你,但你没有出错。
typedef struct s_fct_printf
{
char flag;
char pad[7];
void (*fct)(void*);
} t_fct_printf;
有助于解决填充问题。但是,您必须更改初始化数组的方式。
使用
static const t_fct_printf flags[] =
{
{ 's', "", my_putstr_printf },
{ 'b', "", display_base_2 },
};
否则,编译器会尝试用 my_putstr_printf
初始化成员 pad
,这不是您想要的。
更新
您可以通过使用以下方式避免 pad
大小的硬编码数字 7
:
typedef struct s_fct_printf
{
char flag;
char pad[sizeof(void(*)(void))-1];
void (*fct)(void*);
} t_fct_printf;
感谢@WeatherVane 的建议。
我对你的问题给予了适当的考虑。我不认为添加填充字段是解决方案。它破坏了代码并引入了潜在的未来问题。
我也理解一个质量要求,即所有代码都应该在没有警告或错误的情况下编译。但是,此警告仅供参考,并未指出可能的错误。
我的建议是在警告发生的地方和接受发生的地方明确禁止显示警告。我建议(以 VC 为例):
#pragma warning(disable:4123)
// The compiler will inform that padding will insert 7 bytes after flag,
// which will be unused. This is acceptable.
typedef struct s_fct_printf
{
char flag;
void (*fct)(void*);
} t_fct_printf;
#pragma warning(enable:4123)
我希望你的编译器有类似的机制。