【问题标题】:What's the proper format for a union initializer list?联合初始化列表的正确格式是什么?
【发布时间】:2013-08-24 08:05:22
【问题描述】:

假设我有一个类/结构,其中有一个联合......类似于:

struct Box { union { AS128 intr; struct { AS32 a, b, c, d; }; }; };

为这种数据类型创建初始化列表的正确方法是什么?

Box iMyBoxA = { 10, 10, 100, 100 };
Box iMyBoxB = ( Box ){ 10, 10, 100, 100 };

上面的 'A' 选项在许多情况下都有效,但不是完全可移植的......给出错误“没有已知的转换来自'大括号封闭的初始化列表'的参数 1”。第二个不编译“不能省略围绕子对象初始化的大括号......”

我尝试了其他几种情况,但似乎无法让它跨多个平台编译。

【问题讨论】:

  • 您的工会中有五个独立的成员。你只能使用一个,但你给了四个初始化器。
  • 这个问题很傻,5月初始化一个。
  • 您使用的是哪个编译器?我们可以使用 C99 指定的初始化器吗?
  • 为什么一个联合会有四个相同类型的成员? a, b, c, d 是否应该是嵌套在联合中的结构的成员?

标签: c++ c initialization unions


【解决方案1】:

联合一次只包含一个成员,因此您只用一个值对其进行初始化。

您可以使用Box iMyBoxA = { value }; 来初始化工会的第一个列出的成员,或使用Box iMyBoxA = { .name = value }; 来按名称初始化特定成员。

一些注意事项:

您的代码在联合声明后缺少分号;应该是:

struct Box { union { AS128 intr; AS32 a, b, c, d; }; };

因为你在一个结构体中有一个联合,你应该为初始化器使用两组大括号:

Box iMyBoxA = { { value } };

允许使用带有一组大括号的语法,但可能会引起编译器的警告。

指定初始化程序(初始化程序中的成员名称)是 C 1999 的一项功能。这个问题用 C 和 C++ 标记。 C++ 编译器可能接受也可能不接受指定的初始化程序。在 C 中,您还需要使用 typedefBox 声明为类型或将 Box iMyBoxA… 更改为 struct Box iMyBoxA…

在 C 中,匿名联合是 C 2011 中的新功能。

【讨论】:

  • 感谢您的回复......虽然我实际上在我的问题中输入了错误的内容。请再看一下,看看它是否更有意义。谢谢。
【解决方案2】:

问题中结构和联合定义的原始版本是:

struct Box { union { AS128 intr; AS32 a, b, c, d; } };

这有点不寻常。假设定义了 AS128 和 AS32 类型,则等价于:

struct Box1  // Renamed for convenience of testing
{
    union
    {
        AS128 intr;
        AS32  a;
        AS32  b;
        AS32  c;
        AS32  d;
    };
};

也就是说,它是一个名为 intrAS128 和名为 abcd 的 4 个类型为 AS32 的单独值的联合(其中后 4 个都是占用相同的空间)。

大概,你的想法是:

struct Box2
{
    union
    {
        AS128 intr;
        struct
        {
            AS32  a;
            AS32  b;
            AS32  c;
            AS32  d;
        } s;
    };
};

这使用了 C11 的匿名成员功能(在 ISO/IEC 9899:2011 的前言中列为与 C99 相比的新功能)。 [这个问题现在已经修复,或多或少地反映了这种表示法(使用匿名结构)。请注意,您不能直接指定匿名工会成员,因此至少上面的s 是一个好主意。可以使用没有s 的结构,但我认为除非您可以指定它,否则您不能初始化该结构——您只能指定联合的命名元素。]

使用第一个变体 (struct Box1),您可以初始化没有名称的第一个成员(AS128 intr; 成员):

struct Box1 b1 = { { 1234 } };

外大括号用于结构;内大括号用于(匿名)联合。

或者您可以使用指定的初始化程序指定要初始化的成员:

struct Box1 b2 = { { .a = 1234 } };

请注意,您不能这样做:

struct Box1 b3 = { { .a = 1234, .b = 2341 } };

编译器给出警告(参见下面的示例代码)。

对于第二个变体 (struct Box2),在嵌套结构中,您仍然可以使用未指定的初始化程序或指定的初始化程序,但是这一次,您可以指定结构的所有 4 个成员:

struct Box2 b4 = { { .s = { .a = 32, .b = 65, .c = 48, .d = 97 } } };

示例代码

AS128AS32 类型名称使用有趣的类型。

typedef long AS128;
typedef char AS32;

struct Box1
{
    union
    {
        AS128 intr;
        AS32  a;
        AS32  b;
        AS32  c;
        AS32  d;
    };
};

struct Box2
{
    union
    {
        AS128 intr;
        struct
        {
            AS32  a;
            AS32  b;
            AS32  c;
            AS32  d;
        } s;
    };
};

struct Box1 b1a = { { 1234 } };
struct Box1 b1b = { { .intr = 1234 } };
struct Box1 b1c = { { .a = 32 } };
//struct Box1 b1d = { { .b = 29, .c = 31 } }; // Invalid double initialization
//error: initialized field overwritten [-Werror=override-init]

struct Box2 b2a = { { 1234 } };
struct Box2 b2b = { { .intr = 1234 } };
struct Box2 b2c = { { .s = { .a = 29, .b = 30, .c = 31, .d = 32 } } };

【讨论】:

  • 感谢详细的回复!而且您实际上已经修复了我的错误类型……我的意思是询问您的“ Box2”示例。让我试一试。
  • 不错!你的最后一个例子正是我想要的。谢谢。 :)
  • 其实...最后一个问题。有没有办法省略内部结构的名称?我真的更喜欢struct Box2 b2d = { { 29, 30, 31, 32 } }; 这样的东西,这样我就不必将b2d.a 称为b2d.s.a
  • 只要您指定结构,未命名的初始化程序就可以工作:struct Box2 b2d = { { .s = { 29, 30, 31, 32 } } };。或者你可以将结构放在intr 之前,所以它是工会的第一个成员,然后你会写:struct Box2a b2d = { { { 29, 30, 31, 32 } } };。我没有用编译器验证这一点,但我相信这是真的。
  • 注意我关于在联合中命名结构元素的新评论,以便您可以指定它进行初始化;我无法初始化联合的匿名元素——但我可能没有花足够的时间处理编译器错误消息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-25
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 2020-12-22
相关资源
最近更新 更多