C 使用指向指针数组成员的指针进行静态结构初始化
我试图初始化一个需要指向指针数组的结构成员。其思想是静态声明结构数组以避免初始化开销,因为所有数据在编译时都是固定的和已知的 不幸的是,我无法在Visual Studio 2015下编译代码。下面列出的代码产生以下错误:C 使用指向指针数组成员的指针进行静态结构初始化,c,visual-studio,visual-c++,c99,C,Visual Studio,Visual C++,C99,我试图初始化一个需要指向指针数组的结构成员。其思想是静态声明结构数组以避免初始化开销,因为所有数据在编译时都是固定的和已知的 不幸的是,我无法在Visual Studio 2015下编译代码。下面列出的代码产生以下错误:C2099:初始值设定项不是常量。这看起来很奇怪,因为list仅使用固定大小的字符串文本列表进行初始化 #define DATA_LIST { \ L"some", \ L"example", \ L"data", \
C2099:初始值设定项不是常量
。这看起来很奇怪,因为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
}
};
我还尝试使用指向灵活数组的指针(constwchar\u t*list[];
)。这不是理想的解决方案,因为somedata
将不再能够声明为结构数组。接下来,它还将生成一个警告(C4200:使用的非标准扩展:struct/union中的零大小数组)
另一个想法是将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
}
};
也许我正在监督一些事情,或者是否有一些语言扩展功能可以提供一个优雅的解决方案?欢迎提出任何建议
注意:即使添加了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'
};
最后但并非最不重要的一点是,当使用用字符串文本列表的地址初始化的临时变量初始化列表
成员时,代码最终编译良好,没有任何警告或错误
static const wchar_t *temp[] = DATA_LIST;
static dataset somedata = {
.flag = 2,
.list = temp
};
但是当将temp
声明为指向指针的指针并键入字符串文本列表时,无法再编译代码,因为初始化list
的表达式被标记为活动错误:表达式必须具有常量值
static const wchar_t **temp = (const wchar_t *[])DATA_LIST;
static dataset somedata = {
.flag = 2,
.list = temp // marked as active error
};
如果我决定再次使somedata
非静态,则表达式不再标记为活动错误。但在尝试编译代码时,再次出现以下错误:C2099:初始值设定项不是常量
我想知道Visual Studio 2017是否有相同的行为方式,是否有可用的替代方法以类似的方式组织和处理数据。MSVC对C标准的遵从性较差。作为一种解决方法,您可以使用命名对象而不是复合文字:
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
}
};
我不确定您是否有意将列表设置为非常量,但如果您不打算在运行时写入x_data_list
,则可以将其设置为const
,并将.list
成员的类型设置为const wchar\t*const*
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
}
};
我不确定您是否有意将列表设置为非常量,但如果您不打算在运行时写入x_data_list
,那么您可以将其设置为const
,并将.list
成员的类型设置为const wchar*const*
Visual studio对C99的支持实际上是不存在的。这就是你没能成功的原因。如果您希望MSVC构建代码,请坚持使用C90。16年的时间不足以让MS实现新功能,请再给他们几年。Visual studio对C99的支持几乎不存在。这就是你没能成功的原因。如果您希望MSVC构建您的代码,请坚持使用C90。16年的时间不足以让MS实现新功能,请再给他们几年时间const
应用到左侧,这就是为什么我总是在右侧wchar\u t const*const*
,我发现const-wchar\u t*const*
奇怪,因为人们认为const
适用于右边。const
适用于左边这就是为什么我总是在右边写wchar\u t*const*
,我发现const-wchar\u*const*
奇怪,因为人们认为const
适用于右边。