简体   繁体   English

使用指向指针数组的指针的成员进行静态结构初始化

[英]Static structure initialization with a pointer to array of pointers member

I'm trying to initialize a structure member that needs to point to an array of pointers. 我正在尝试初始化一个需要指向指针数组的结构成员。 The idea is to declare the array of structures statically to avoid initialization overhead since all the data is fixed and known at compile time. 想法是静态声明结构数组,以避免初始化开销,因为所有数据都是固定的,并且在编译时已知。

Unfortunately, I cannot get the code to compile under Visual Studio 2015 . 不幸的是,我无法在Visual Studio 2015下编译代码。 The code listed below produces the following error: C2099: initializer is not a constant . 下面列出的代码产生以下错误: C2099: initializer is not a constant Which seems odd because list is only initialized with a fixed sized list of string literals. 这似乎很奇怪,因为list仅使用固定大小的字符串文字列表进行初始化。

#define DATA_LIST { \
    L"some",        \
    L"example",     \
    L"data",        \
    L"in a list",   \
    NULL            \
}

#define INFO_LIST { \
    L"another",     \
    L"list",        \
    L"with",        \
    L"some",        \
    L"info",        \
    NULL            \
}

typedef struct data {
    unsigned int flag;
    const wchar_t **list;
} dataset, *pdataset;

static dataset somedata[] = {
    {   .flag = 2,
        .list = (const wchar_t *[])DATA_LIST // C2099
    },
    {   .flag = 4,
        .list = (const wchar_t *[])INFO_LIST // C2099
    }
};

I've also tried to use a pointer to a flexible array ( const wchar_t *list[]; ). 我还尝试使用一个指向灵活数组的指针( const wchar_t *list[]; )。 Not the ideal solution because somedata will no longer be able to be declared as an array of structures. 这不是理想的解决方案,因为将不再能够将somedata声明为结构数组。 Next to that, it will also produce a warning (C4200: nonstandard extension used: zero-sized array in struct/union) . 紧接着,它还会产生警告(C4200: nonstandard extension used: zero-sized array in struct/union)

typedef struct data {
    unsigned int flag;
    const wchar_t *list[]; // C4200 (somedata can no longer be an array of structures)
} dataset, *pdataset;

static dataset somedata = {
    .flag = 2,
    .list = DATA_LIST
};

Another idea was to define list as a pointer to a fixed size array of pointers. 另一个想法是将list定义为指向固定大小的指针数组的指针。 But this requires the dataset structure to be defined with a list member that is large enough to hold the largest list. 但这需要使用list成员定义dataset结构,该list成员足够大以容纳最大列表。 Also not ideal when there are lots of small lists and one single large list. 当有很多小列表和一个大列表时,也不理想。

typedef struct data {
    unsigned int flag;
    const wchar_t *list[sizeof (wchar_t *[])INFO_LIST / sizeof *(wchar_t *[])INFO_LIST];
} dataset, *pdataset;

static dataset somedata[] = {
    {   .flag = 2,
        .list = DATA_LIST
    },
    {   .flag = 4,
        .list = INFO_LIST
    }
};

Maybe I'm overseeing something or is there some language extension feature available that can provide an elegant solution? 也许我正在监督某些事情,或者是否有一些语言扩展功能可以提供一个优雅的解决方案? Any suggestions are welcome. 欢迎任何建议。

Note: even though the visual-c++ tag is added, the code is compiled as C code. 注意:即使添加了visual-c++标记,该代码仍被编译为C代码。


Another interesting thing to add which might be related, is that when somedata is declared as non-static (thus without the static keyword), the compiler will produce some warnings but is able to compile the code. 可能要添加的另一件有趣的事情是,当somedata被声明为非静态数据(因此没有static关键字)时,编译器将产生一些警告,但能够编译代码。 By declaring somedata as non-static, the constraint is removed that forces the data used for initializing somedata to be known at compile time. 通过声明somedata为非静止的,该约束被移除,迫使用于初始化数据somedata在编译时是已知的。

As indicated by the compilation warnings, it seems that the compiler temporarily stores the address of the list of string literals in an automatic variable before initializing the list member with it. 如编译警告所示,似乎编译器在用它初始化list成员之前,将字符串文字列表的地址临时存储在一个自动变量中。 This remains speculation, though. 不过,这仍然是猜测。 Maybe someone experienced can shed some light on what is actually happening here. 也许经验丰富的人可以对这里实际发生的事情有所了解。

typedef struct data {
    unsigned int flag;
    const wchar_t **list;
} dataset, *pdataset;

// C4221: nonstandard extension used: 'list': cannot be initialized using
//        address of automatic variable '$S1'
// C4204: nonstandard extension used: non-constant aggregate initializer
dataset somedata = {
    .flag = 2,
    .list = (const wchar_t *[])DATA_LIST // note: see declaration of '$S1'
};

Last but not least, when using a temporary variable initialized with the address of the list of string literals to initialize the list member, the code finally compiles fine without any warnings or errors. 最后但并非最不重要的一点是,当使用使用字符串文本列表的地址初始化的临时变量初始化list成员时,代码最终可以正常编译,而不会发出任何警告或错误。

static const wchar_t *temp[] = DATA_LIST;

static dataset somedata = {
    .flag = 2,
    .list = temp
};

But when declaring temp as a pointer to a pointer and typecasting the list of string literals, the code can no longer be compiled as the expression that initializes list becomes marked as an active error: expression must have a constant value 但是,当将temp声明为指向指针的指针并类型转换字符串文字列表时,由于初始化list的表达式被标记为活动错误,因此无法再编译该代码: expression must have a constant value

static const wchar_t **temp = (const wchar_t *[])DATA_LIST;

static dataset somedata = {
    .flag = 2,
    .list = temp // marked as active error
};

If I then decide to make somedata non-static again, the expression is no longer marked as an active error. 如果我随后决定再次使somedata非静态,则该表达式不再标记为活动错误。 But when trying to compile the code, the following error comes back up again: C2099: initializer is not a constant 但是,当尝试编译代码时,再次出现以下错误: C2099: initializer is not a constant

I'm wondering if Visual Studio 2017 behaves the same way and if there is an alternative method available to organize and process the data by similar means. 我想知道Visual Studio 2017行为方式是否相同,是否存在其他可用的方法来通过类似方式组织和处理数据。

MSVC has poor compliance to the C Standard. MSVC对C标准的合规性很差。 As a workaround you can use named objects instead of compound literals: 解决方法是,可以使用命名对象代替复合文字:

static const wchar_t *x_data_list[] = DATA_LIST;
static const wchar_t *x_info_list[] = INFO_LIST;

static dataset somedata[] = {
    {   .flag = 2,
        .list = x_data_list
    },
    {   .flag = 4,
        .list = x_info_list
    }
};

I'm not sure whether you intentionally made your lists non-const, but if you are not planning to write to x_data_list at runtime then you can make it const and give the .list member the type const wchar_t * const * . 我不确定您是否有意使列表成为非常量,但是如果您不打算在运行时写入x_data_list ,则可以使其成为const并为.list成员指定const wchar_t * const *的类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM