【发布时间】:2017-11-12 20:24:58
【问题描述】:
我正在尝试初始化一个需要指向指针数组的结构成员。这个想法是静态声明结构数组以避免初始化开销,因为所有数据在编译时都是固定的和已知的。
很遗憾,我无法在Visual Studio 2015 下编译代码。下面列出的代码会产生以下错误:C2099: initializer is not a constant。这似乎很奇怪,因为 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
}
};
我还尝试使用指向灵活数组的指针 (const wchar_t *list[];)。这不是理想的解决方案,因为somedata 将不再能够被声明为结构数组。除此之外,它还会产生一个警告(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
};
另一个想法是将list 定义为指向固定大小的指针数组的指针。但这需要使用足够大的list 成员来定义dataset 结构以容纳最大的列表。当有很多小列表和一个大列表时也不理想。
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
}
};
也许我正在监督某些事情,或者是否有一些语言扩展功能可以提供优雅的解决方案?欢迎提出任何建议。
注意:即使添加了visual-c++标签,代码也会编译为C代码。
另一个可能相关的有趣的事情是,当somedata 被声明为非静态(因此没有static 关键字)时,编译器会产生一些警告但能够编译代码。通过将somedata 声明为非静态,移除了强制用于初始化somedata 的数据在编译时已知的约束。
如编译警告所示,编译器似乎在用它初始化 list 成员之前将字符串文字列表的地址临时存储在自动变量中。不过,这仍然是猜测。也许有经验的人可以对这里实际发生的事情有所了解。
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'
};
最后但同样重要的是,当使用以字符串文字列表的地址初始化的临时变量来初始化 list 成员时,代码最终编译良好,没有任何警告或错误。
static const wchar_t *temp[] = DATA_LIST;
static dataset somedata = {
.flag = 2,
.list = temp
};
但是当将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
};
如果我决定再次将somedata 设为非静态,则表达式不再标记为活动错误。但是在尝试编译代码时,再次出现以下错误:C2099: initializer is not a constant
我想知道Visual Studio 2017 的行为方式是否相同,是否有替代方法可以通过类似方式组织和处理数据。
【问题讨论】:
-
Visual Studio 对 C99 的支持几乎不存在。这是您无法使其正常工作的根源。如果您希望 MSVC 构建您的代码,请坚持使用 C90。
-
16 年时间不足以让 MS 实现新功能,再给他们几年时间
标签: c visual-studio visual-c++ c99