【问题标题】:problem with assigning value to a unionized field of a struct将值分配给结构的联合字段的问题
【发布时间】:2020-02-03 12:30:28
【问题描述】:

我是新来的,希望能得到一些帮助。 在做了一个关于structsunions的教程之后,我实践了我所学的,并且想结合两个想法。但是我遇到了一个错误,我已经尝试解决了几个小时,但没有任何运气。

代码是:

void main(){

    typedef enum {INDIV, OUNCE, POUND } quantity;

    typedef union{

        short individual;
        float pound;
        float ounce;

    } amount;

    typedef struct{

        char *brand;
        amount theAmount;

    } orangeProduct;

    orangeProduct productOrdered;

    quantity quantityType = OUNCE;

    switch(quantityType)
    {
        case INDIV:
            productOrdered = {"Chiquita", .theAmount.individual = 13 };
            printf("You bought %d oranges\n\n", productOrdered.theAmount.individual)
            break;

    }
}

我也有其他情况,但这没关系:如果我解决了第一个问题,我将解决所有问题。 目标是拥有可以容纳橙子品牌的结构,并为每个品牌容纳购买的数量、正确的重量类型。

问题出在这行:

productOrdered = {"Chiquita", productOrdered.theAmount.individual = 13 };

我的gcc compiiler(使用codeBlocks)对我大喊:

错误:“{”标记之前的预期表达式|

而且,无论我怎么尝试,都无济于事。

请帮忙。

【问题讨论】:

    标签: c struct unions


    【解决方案1】:

    分配给结构

    将大括号 ({ .... }) 与结构的初始值列表一起使用的语法只能在定义结构时使用,如下所示:

    orangeProduct productOrdered = { "Chiquita", { 13 } };
    

    你不能在作业中使用它;此语句语法不正确:

    productOrdered = { "Chiquita", { 13 } };
    

    有两种方法可以为结构分配值,而不是在定义结构时对其进行初始化。一种是单独分配给每个成员:

    productOrdered.brand = "Chiquita";
    productOrdered.theAmount.individual = 13;
    

    另一个是从另一个结构中复制它:

    productOrdered = SomeOtherProduct;
    

    我们可以将上述内容与另一个称为复合文字的 C 功能一起使用。可以在表达式中使用复合文字来提供对象而无需为其命名。复合文字的一般形式是:

    (type) { initial values... }
    

    虽然(type) 看起来像演员表,但事实并非如此。此语法定义了一个对象,它可以使用与声明中使用的初始值相同的语法。这意味着我们可以初始化一个复合文字并将其分配给一个结构:

    productOrdered = (orangeProduct) { "Chiquita", { 13 } };
    

    关于分配给结构的其他说明

    以下所有都具有相同的效果:

    productOrdered = (orangeProduct) { "Chiquita", { 13 } };
    productOrdered = (orangeProduct) { "Chiquita", 13 };
    productOrdered = (orangeProduct) { "Chiquita", { .individual = 13 } };
    productOrdered = (orangeProduct) { "Chiquita", .theAmount.individual = 13 };
    

    在其中的第一个中,内大括号表示我们正在为主对象的子对象提供初始值——用于orangeProduct 内的联合amount。如第二行所示,这不是必需的,因为如果省略大括号,编译器将采用未分组的初始值并将它们分配给子对象的成员。但是,最好明确地包含大括号,因为它可以避免更复杂的聚合中的错误,并有助于向人类读者传达意图。

    第三种和第四种形式表明我们可以使用他们的名字来初始化成员。这种形式称为指定初始值设定项。当您跳过结构中的成员或想要初始化除第一个列出的成员之外的联合成员时,它们最有用。

    但是,另一个答案提出了这个错误的说法:

    productOrdered = (orangeProduct){"Chiquita", productOrdered.theAmount.individual = 13 }
    

    这是错误的,因为productOrdered.theAmount.individual = 13 不仅仅是一个初始值;它是一个赋值表达式。它将 13 分配给 productOrdered.theAmount.individual。这样做的问题是,整个语句还将值分配给productOrdered,包括productOrdered.theAmount.individual。这违反了 C 2018 6.5 2 中的规则,即:

    如果标量对象的副作用相对于同一标量对象的不同副作用或使用同一标量对象的值的值计算是未排序的,则行为未定义......

    productOrdered.theAmount.individual 的两个赋值是无序的,因为 C 标准中没有规则说明赋值何时发生相对于彼此。 (当赋值表达式更新对象的值时,称为副作用,它不是表达式的主要评估操作的一部分。)

    其他说明

    main 应该用int main(void)int main(int argc, char *argv) 声明,而不是void main()。它也可以用 C 实现允许的特定形式声明。

    在您的代码中包含#include <stdio.h> 以声明printf

    在这一行添加分号:

    printf("You bought %d oranges\n\n", productOrdered.theAmount.individual)
    

    【讨论】:

    • 嗨,埃里克,很好的回答,我学到了很多,谢谢!又花了几个小时阅读补充概念。如果你能帮我做一些澄清,那将是晚餐:1.如果我想分配一个值,而不是给工会的第一个成员,让我们说第二个 - “磅” - 我将不得不使用您在上面编写的 4 种方法中的第三种还是第四种? (第一个和第二个对我没有帮助,对吗?) 2.我又看了一遍,发现 6.5 2 评论,看了几遍,我还是不清楚,请您自己解释一下单词?
    • @ArieCharfnadel:是的,要初始化除第一个列出的成员之外的联合成员,您必须使用指定的初始化程序,如答案中的第三或第四种形式所示。
    • @ArieCharfnadel:关于副作用和顺序的规则过于复杂,无法在评论中完全解释。基本上,表达式具有主要效果(3*4 的计算结果为 12,a = 3 的计算结果为 3),而某些表达式具有副作用(x++ 增加了 xa = 3a 设置为 3)。 C 标准为其中一些定义了一些排序,并留下了一些未指定的排序。一条规则是,表达式语句中的所有副作用在后面的语句中的副作用开始之前都是完整的。...
    • ... 所以你可以在一个语句中使用a++,在另一个语句中使用a = 3,它们不会交织在一起。但是,如果它们在同一个语句中,它们可能会交织在一起——C 标准中可能没有规则说一个在另一个开始之前完成。 C 第 6.5 条第 2 段说,如果程序这样做时会产生修改同一对象的副作用,则行为未定义。此外,如果对对象的一种副作用可能与对对象值的一次使用交织在一起,则行为未定义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-23
    • 1970-01-01
    • 2010-12-26
    • 2014-04-03
    • 2021-06-24
    相关资源
    最近更新 更多