Clang中结构填充的警告

jw5wzhpr  于 2023-08-03  发布在  其他
关注(0)|答案(3)|浏览(106)

我创建了以下结构:

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;


有没有好的解决办法?

jogvjijk

jogvjijk1#

我对你的问题给予了应有的考虑。我不认为添加填充字段是解决方案。它会破坏代码并引入潜在的未来问题。
我还理解一个质量要求,即所有代码都应该在没有警告或错误的情况下编译。但是,此警告仅提供信息,并不指出可能的错误。
我的建议是,在警告发生的地方和接受警告的地方,明确地抑制它。我建议(以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)

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

mkh04yzy

mkh04yzy2#

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的建议。

bnl4lu3b

bnl4lu3b3#

您似乎运行在64位系统上。char占用一个字节,编译器希望函数指针从64位(8字节)边界开始。因此,它需要在char之后填充7个字节以对齐函数指针。
编译器只会通知您这一点(由于隐含的选项-Wpadded),但代码不包含错误。

相关问题