我正在使用带有3个正式记录成员的结构的库,但实际上包含4个。最后一个是用于填充的字节数组。这是C保持ABI兼容的常见技术:最后添加一堆字节,如果以后的版本将成员添加到结构中,则该填充区域会相应地缩小。总共,结构的大小保持不变。
,但是现在我必须在C 中使用此结构,并且我将其用于静态const值,因此我需要使用初始化器列表初始化它。因此,这样:
static const foo_struct foo = { 1, 2, 3 };
由于这不会初始化第四个值,因此GCC打印出来:
warning: missing initializer for member ‘foo_struct::padding’ [-Wmissing-field-initializers]
像foo(1,2,3)这样的构造函数语法是行不通的,因为这是C结构。并且将其设置为{0}也不是选项,因为我必须初始化前三个成员。
是否有C 11/C 14符合此警告的方式?
编辑:简单地使用{1、2、3、0}可能起作用,但由于填充区域没有记录,但不稳定。另外,如果将来版本添加一个会员,则最多将总结5个成员,并且警告将返回。
您只能写下这样的函数:
template <class ... T>
constexpr foo_struct make_foo_struct(T ... t) {
return foo_struct{t..., 0};
}
static const auto foo = make_foo_struct(1, 2, 3);
您无需禁用任何警告。作为奖励,如果将另一个字段添加到结构中,则警告将返回(因为然后您将有5个成员,并且只能初始化4)。这也很方便,因为如果您要创建很多foos,并且添加了一个新领域,您不在乎(假设是布尔人,您始终想成为true
),则可以更改make_foo_struct
以按照方式初始化它您想要,不修改所有呼叫网站。
您当然可以在make_foo_struct
中写出类型和参数名称,而不是使用T...
;它使事情变得更加明确,但也需要更多的维护和较小的灵活性。
如果删除了填充物,则应该无法编译,并且您只需要修复此一个功能即可。但是,如果您不喜欢那样,另一个选择是在函数中以编译器的pragma进行警告。
template <class ... T>
constexpr foo_struct make_foo_struct(T ... t) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
return foo_struct{t...};
#pragma GCC diagnostic pop
}
和地狱,我将给出第三种选择。如果您有3个命名成员,并且他们的名字稳定,并且您只想初始化它们并将其零零,那么您可以做:
constexpr foo_struct make_foo_struct(int x, int y, int z) {
foo_struct f{};
f.x = x; f.y = y; f.z = z;
return f;
}
编译器应愉快地将其优化。
c 是与C相兼容的...
由于库结构是 a c struct,因此与您在C中的字节完全相同。当填充字节未记录时,它们是结构定义的一部分,使用第四个初始器(零)会很好,需要。实际上,您别无选择,只能填充PAD字节为零。
示例:
// in the library .h
struct foo_struct
{
int first, second, third;
unsigned char padding[256 - 3 * sizeof(int)];
};
// in your cpp
// your could do this:
static const foo_struct foo1 = { 1, ,2, 3, 0 }; // add 0, since it's needed.
// or if you really want to create this boiler plate...
static const foo_struct foo2; // note that it is initialized to zero at startup
// as all static variables are, unless a value is specified
static bool InitFoo2();
static bool fooInitialized = InitFoo2(); // it does waste some data space...
static bool InitFoo2()
{
p = const_cast<foo_struct*>(&foo2);
memset(p, 0, sizeof(foo2)); // not needed in this particular case
// but doesn't hurt to do be explicit.
p->first = 6;
p->second = 7;
p->third = 42;
return true;
}
// Top keep your code compatible with future version, you have no choice,
// but to clear the padding bytes of any foo_struct before using the library.
// Let's look at dynamic allocation, the required data space is the
// exact same size as for static memory allocation.
//
foo_struct* bar()
{
// sizeof(foo_struct) = 256 bytes, padding MUST be reset,
// so your app is compatible with future versions of the library.
//
foo_struct* p = (foo_struct*)malloc(sizeof(foo_struct));
if (p)
{
// By clearing the foo_struct this way, you do not ever need to
// the undocumented members.
memset(p, 0, sizeof(*p));
p->first = 6;
p->second = 7;
p->third = 42;
}
return p;
}
我个人去寻求此解决方案:
static const foo_struct foo = { 6, 7, 42, 0 };