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)

我希望你的编译器有类似的机制。