Home > Software engineering >  conditional initialization of static arrays, using compound literals
conditional initialization of static arrays, using compound literals

Time:03-18

#include <stdint.h>

#define INIT_UINT32 1
#define INIT_INT32  2

#define INIT INIT_INT32

typedef union
{
  uint32_t a;
  int32_t  b;
} Foo_t;

/* Why does this compile... */
static Foo_t foo_static = INIT == INIT_INT32 ?
    (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX };

/* but this doesn't? */
static Foo_t foo_static_array[] =
{
  INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }
};

int main(void)
{
}

When compiled, the conditional initialization of foo_static using compound literals succeeds, but the conditional initialization of foo_static_array using compound literals fails. Following are the compile errors.

$ gcc test.c
test.c:4:21: error: initializer element is not constant
    4 | #define INIT_INT32  2
      |                     ^
test.c:6:14: note: in expansion of macro ‘INIT_INT32’
    6 | #define INIT INIT_INT32
      |              ^~~~~~~~~~
test.c:21:3: note: in expansion of macro ‘INIT’
   21 |   INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }
      |   ^~~~
test.c:4:21: note: (near initialization for ‘foo_static_array[0]’)
    4 | #define INIT_INT32  2
      |                     ^
test.c:6:14: note: in expansion of macro ‘INIT_INT32’
    6 | #define INIT INIT_INT32
      |              ^~~~~~~~~~
test.c:21:3: note: in expansion of macro ‘INIT’
   21 |   INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }
      |   ^~~~

Can anyone explain why this is the case?

CodePudding user response:

GCC is providing the former initialization as an extension to the C standard. It is not providing the latter. This is a GCC choice, not mandated by the standard. With -pedantic, GCC complains about both.

The relevant passage in the C standard is C 2018 6.7.9 4:

All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.

This is in a Constraints section, which means a conforming compiler must diagnose it, as GCC does when -pedantic is used, although it still accepts the code and completes compilation. Without -pedantic, GCC accepts both but only diagnoses the latter.

The GCC documentation on C extensions is silent about the reason for this difference. Its clause 6.27 says that initializers for aggregates with automatic storage duration are not required to be constant expressions, but there is no subclause in the C extensions clause that addresses initializers for static objects.

To make your code strictly conforming, you should not use these initializers in either the non-array or the array initialization.

  •  Tags:  
  • c c99
  • Related