用嵌套结构初始化联合

贝辛

我正在将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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

初始化嵌套结构定义

来自分类Dev

用pyparsing解析嵌套结构

来自分类Dev

嵌套结构初始化文字

来自分类Dev

这是GCC错误吗?用联合初始化结构

来自分类Dev

用模板初始化结构

来自分类Dev

嵌套结构初始化是否取决于作用域?

来自分类Dev

用括号括起来的初始化程序列表初始化结构时出错

来自分类Dev

联合初始化

来自分类Dev

用嵌套结构数组初始化结构

来自分类Dev

初始化嵌套结构

来自分类Dev

在golang中的嵌套结构中初始化结构数组

来自分类Dev

用malloc初始化结构内部的结构?

来自分类Dev

结构初始化中的匿名联合

来自分类Dev

私有嵌套结构的std :: array无法初始化(错误C2248)

来自分类Dev

用数组元素初始化结构的数组

来自分类Dev

用clang vs gcc进行联合零初始化

来自分类Dev

用指针(C)初始化结构的成员

来自分类Dev

用{0}初始化结构

来自分类Dev

使用指定的初始值设定项来初始化带有`char []`成员的嵌套结构

来自分类Dev

如何在Julia中初始化/构造深层嵌套结构?

来自分类Dev

用联合返回结构的初始化

来自分类Dev

如何使用C ++ 20指定的初始化程序在结构中初始化联合

来自分类Dev

初始化包含联合的结构

来自分类Dev

用malloc初始化结构

来自分类Dev

初始化嵌套结构

来自分类Dev

用clang vs gcc进行联合零初始化

来自分类Dev

用主干关系创建嵌套结构

来自分类Dev

嵌套结构初始化

来自分类Dev

c ++嵌套结构初始化和访问成员