C: Initializing struct variables after declaration

后端 未结 3 1086
刺人心
刺人心 2020-12-29 23:11

I encountered this recently but could not figure out why the language would allow b = c; below and fail b = {3, 4}. Is there an issue with allowing the latter ?

<         


        
相关标签:
3条回答
  • 2020-12-29 23:34

    It fails because {3, 4}, though it's a valid initializer, is not an expression (at least it isn't in C; see below for more about C++).

    Every expression in C has a type that can be determined by examining the expression itself. {3, 4} could potentially be of type struct T, or int[2] (an array type), or any of a myriad of other types.

    C99 added a new feature called compound literals that use a similar syntax to initializers, but let you specify the type, creating an expression:

    b = (struct T){3, 4};
    

    Note that the (struct T) is not a cast operator; it's part of the syntax of a compound literal.

    For more information on compound literals, see section 6.5.2.5 of the draft C11 standard.

    Compound literals were introduced by the 1999 ISO C standard (C99). If your compiler doesn't support C99 or better (*cough*Microsoft*cough*), then you won't be able to use them.

    If you're using C++ (which, don't forget, is a different language), it doesn't support compound literals, but there may be an alternative. As Potatoswatter points out in a comment, this:

    b = T{3, 4};
    

    is valid in C++11 (but not in earlier versions of the C++ language). This is covered in section 5.2.3 [expr.type.conf] of the C++ standard.

    For that matter, this:

    b = {3, 4};
    

    is also valid C++11 syntax. This form can be used in a number of specified contexts, including the right side of an assignment. This is covered in section 8.5.4 [dcl.init.list] of the C++ standard.

    One recent draft of the C++ standard is N3485.

    (g++ supports C99-style compound literals in C++ as an extension.)

    And if you're stuck with a pre-C99 compiler, you can always write your own initialization function, such as:

    struct T init_T(int x, int y) {
        struct T result;
        result.x = x;
        result.y = y;
        return result;
    }
    
    /* ... */
    
    struct T obj;
    /* ... */
    obj = init_T(3, 4);
    

    It's an annoying amount of extra work (which is why C99 added compound literals), but it does the job. On the other hand, in most cases you're probably better off using initialization:

    struct T obj;
    /* ... */
    {
        struct T tmp = { 3, 4 };
        obj = tmp;
    }
    

    Which is better probably depends on how your program is structured.

    0 讨论(0)
  • 2020-12-29 23:39

    Because you didn't use the correct C99 or C11 'compound literal' notation:

    b = (struct T){ 3, 4 };
    

    See §6.5.2 Postfix operators and §6.5.2.5 Compound literals in ISO/IEC 9899:2011 for more information (amongst other places).

    ( type-name ) { initializer-list }
    ( type-name ) { initializer-list , }

    0 讨论(0)
  • 2020-12-29 23:40

    Because that's the definition of the language... I don't think there is any particular reason other than "it makes it harder to write the compiler to allow for this".

    You could do b = T{3, 4} if you have a C++ 11 compiler.

    0 讨论(0)
提交回复
热议问题