对Clang中的struct padding的警告

时间:2016-11-17 18:20:04

标签: c padding

我创建了以下结构:

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;

有一个很好的解决方案吗?

3 个答案:

答案 0 :(得分:3)

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 },
};

否则,编译器会尝试使用pad初始化成员my_putstr_printf,这不是您想要的。

<强>更新

您可以使用以下内容避免使用7大小为pad的硬编码号码

typedef struct  s_fct_printf
{
  char          flag;
  char          pad[sizeof(void(*)(void))-1];
  void          (*fct)(void*);
}               t_fct_printf;

感谢@WeatherVane的建议。

答案 1 :(得分:3)

我考虑了你的问题。我不认为添加填充字段是解决方案。它破坏了代码并引入了潜在的未来问题。

我也理解所有代码应该编译而没有警告或错误的质量要求。但是,此警告仅提供信息,并未指出可能的错误。

我的建议是在发生这种警告的地点和接受发生的地方明确禁止这种警告。我建议(以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)

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

答案 2 :(得分:1)

似乎你在64位系统上运行。 char占用一个字节,编译器希望让函数指针在字64边界上开始。因此,它需要在char之后填充7个字节以对齐函数指针。

编译器似乎只是通知你,但你没有犯错误。