我正在将C99代码移植到C ++(14或17),并且在许多地方都使用了列表初始化程序。现在,我遇到了编译错误,并且想知道初始化由结构嵌套的联合的最简单方法。例如,C中的以下代码片段可以正常工作:
#include <stdint.h>
typedef union Word_t
{
uint32_t word32Bits;
struct
{
uint16_t leastSignificant16Bits;
uint16_t mostSignificant16Bits;
};
} Word_t;
int main()
{
Word_t w1 = (Word_t) {.word32Bits = 0x1234ABCD};
printf("%x\n", w1.word32Bits);
Word_t w2 = (Word_t) {.mostSignificant16Bits = 0x1234, .leastSignificant16Bits = 0xABCD};
printf("%x\n", w2.word32Bits);
return 0;
}
$ gcc test.c --std=c99 -o a && ./a
1234abcd
1234abcd
但是,在C ++中,它不会编译:
#include <stdint.h>
typedef union Word_t
{
uint32_t word32Bits;
struct
{
uint16_t leastSignificant16Bits;
uint16_t mostSignificant16Bits;
} _word16Bits;
} Word_t;
int main()
{
Word_t w1 = (Word_t) {.word32Bits = 0x1234ABCD};
printf("%x\n", w1.word32Bits);
Word_t w2 = (Word_t) {.mostSignificant16Bits = 0x1234, .leastSignificant16Bits = 0xABCD};
printf("%x\n", w2.word32Bits);
return 0;
}
```bash
$ g++ test.c --std=c++14 -o a && ./a
test.c: In function ‘int main()’:
test.c:57:92: error: ‘Word_t’ has no non-static data member named ‘mostSignificant16Bits’
Word_t w2 = (Word_t) {.mostSignificant16Bits = 0x1234, .leastSignificant16Bits = 0xABCD};
我发现的工作量解决方案是将其初始化为零,然后按如下所示设置结构的内部值:
int main()
{
Word_t w1 = (Word_t) {.word32Bits = 0x1234ABCD};
printf("%x\n", w1.word32Bits);
Word_t w2 = (Word_t) {.mostSignificant16Bits = 0x1234, .leastSignificant16Bits = 0xABCD};
Word_t w2 = {0};
w2._word16Bits = {0x1234, 0xABCD};
return 0;
}
哪个可行,但是它不允许我明确地.mostSignificant16Bits = 0x1234
举例说明-我认为这很有用,特别是在阅读代码时。
我尝试了几项操作,例如定义静态成员,创建用户定义的构造函数,但仍然不知道如何简化我要做的重构。理想情况下,Word_t w2 = (Word_t) {.mostSignificant16Bits = 0x1234, .leastSignificant16Bits = 0xABCD}
当所有更改都在的定义中完成时,我想保留变量声明的样子Word_t
。
聚合初始化中指定的初始化程序正式是C ++ 20标准的一部分。
但是与C99相比,它们受到了严重的限制:
在您的情况下,可以编译以下内容,但无法提供您期望的显式命名所带来的灵活性:
Word_t w2 = (Word_t) {._word16Bits { .leastSignificant16Bits = 0xABCD, .mostSignificant16Bits = 0x1234} };
首先,此代码(如果可行)不是可移植的:它假定目标体系结构的字节序很少。
第二,这在这里至关重要,C ++对联合有严格的约束。考虑到对象生命周期的一致性,这些是必需的。特别是:
[class.union] / 1:在联合中,最多可以随时激活一个非静态数据成员,即,最多可以将一个非静态数据成员的值存储在随时工会。
因此,如果在一个成员处于活动状态(初始化程序中使用的一个成员)的情况下构造联合,则另一个成员处于非活动状态,因此您不应访问它。预见的唯一例外不适用于您的情况:
[注意:为了简化并集的使用,做出了一项特殊保证:如果标准布局并集包含多个共享共同初始序列的标准布局结构,并且此标准布局并集类型的对象包含以下其中之一:在标准布局结构中,允许检查任何标准布局结构成员的公共初始序列;—尾注]
该标准还提供了有关更改联盟的活动成员的方式的提示:
[注意:通常,必须使用显式的析构函数调用和放置新的运算符来更改联合的活动成员。—尾注]
据说对于简单的标量类型,它可以像您期望的那样在大多数主流编译器上编译和工作。
但是,要点是,您对联合的使用与标准不兼容。它是UB,即使现在可以在某些实现上使用,在每个新的编译器版本中,您也无法保证它会继续运行,从而使您的所有投资面临风险。
C99对联合的约束比C ++少。但是,对于设置另一个工会成员时在一个工会成员中可能读取的值,它也不能提供任何保证:
6.2.6.1/7:当值存储在联合类型的对象的成员中时,与该成员不对应但与其他成员对应的对象表示形式的字节采用未指定的值。
在附件C99 / J中提到,这种联合使用是未指定的行为,可能会导致可移植性问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句