Search code examples
cgccclangc99compound-literals

clang and gcc different behavior with compound literal


Came across compound literal recently, and as far as I understand it, the following is the correct way of using it. Fortunately, it works both with gcc and clang on ubuntu.

int main() {
  int *p = (int []) {1, 2};
  return 0;
}

However, I notice another way of using compound literal, shown below. It feels a bit weird; this is just array initializer. The following code compiles fine with clang, but failed with gcc, array initialized from non-constant array expression.

int main() {
  int p[] = (int []) {1, 2};
  return 0;
}

Is this intentional or what?

ENV:

  • gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
  • Ubuntu clang version 3.5-1ubuntu1 (trunk) (based on LLVM 3.5)

CMD:

  • gcc test.c
  • clang test.c

Solution

  • Short answer: Clang confesses that the program uses an extension

    Accepting what you wrote, int p[] = (int []) {1, 2};, is a Clang extension. GCC is allowed to reject it, because it is not part of C99 (the C99 standard introduced compound literals and can be used as reference).

    In fact, my version of Clang can be made to emit a warning on your program. It is funny that it calls your line a “GNU extension”:

    ~ $ clang -std=c99 -pedantic t.c
    t.c:2:7: warning: initialization of an array of type 'int []' from a compound
          literal of type 'int [2]' is a GNU extension
          [-Wgnu-compound-literal-initializer]
      int p[] = (int []) {1, 2};
          ^     ~~~~~~~~~~~~~~~
    1 warning generated.
    ~ $ clang -v
    Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
    Target: x86_64-apple-darwin13.4.0
    Thread model: posix
    

    Long answer

    The line int p[] = (int []) {1, 2}; is a declaration. It should follow the syntax given in clause 6.7:

    6.7 Declarations

    Syntax

    1

    declaration:
        declaration-specifiers init-declarator-listopt ;
    
    declaration-specifiers:
        storage-class-specifier declaration-specifiersopt
        type-specifier declaration-specifiersopt
        type-qualifier declaration-specifiersopt
        function-specifier declaration-specifiersopt
    
    init-declarator-list:
        init-declarator
        init-declarator-list , init-declarator
    
    init-declarator:
        declarator
        declarator = initializer

    All lies on the definition of initializer, which can be found in 6.7.8:

    6.7.8 Initialization

    Syntax

    1

    initializer:
        assignment-expression
        { initializer-list }
        { initializer-list , }
    …

    12 The rest of this subclause deals with initializers for objects that have aggregate or union type.

    16 Otherwise, the initializer for an object that has aggregate or union type shall be a brace-enclosed list of initializers for the elements or named members.

    The emphasis in 6.7.8:16 is mine. Basically, this is the part of the C99 standard that your program does not satisfy.