~mcf/cproc#75: 
Explicit Types Confuse Initializer

I'm not 100% sure if this is a bug, but both clang and gcc accept it without complaint. cproc throws an error: initializer is not a constant expression error when explicitly naming struct types in initializers. I got in the habit of doing this back when initializer "type inference" was worse and noticed it while trying to compile a program of mine.

Input: struct dummy { char *label; };

struct dummy str = (struct dummy){.label = "Redraw"};

Result: testcase.c:6:71: error: initializer is not a constant expression

Expected: compiles cleanly. The code does compile cleanly if you remove the (struct dummy) on the initializer line.

Status
RESOLVED INVALID
Submitter
~tekk
Assigned to
No-one
Submitted
1 year, 6 months ago
Updated
1 year, 6 months ago
Labels
No labels applied.

~mcf 1 year, 6 months ago

Thanks for the clear report and test case.

This syntax is perfectly fine for initializing local variables inside a function, but not for static or global variables. The C standard describes this restriction in 6.7.9p4:

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

What you have here on the right hand side is a compound literal expression, which is not a constant expression or string literal. A constant expression must be one of the following (6.6p7):

  • an arithmetic constant expression,
  • a null pointer constant,
  • an address constant, or
  • an address constant for a complete object type plus or minus an integer constant expression.

I believe the reason why this works in gcc and clang is because of 6.7p10:

An implementation may accept other forms of constant expressions.

But this is not something you can rely upon in your code. And indeed, if you enable -Wpedantic, gcc will warn about this:

test.c:2:20: warning: initializer element is not constant [-Wpedantic]
    2 | struct dummy str = (struct dummy){.label = "Redraw"};

The reason that struct dummy str = {.label = "Redraw"}; works is because there is only one expression in the initializer, the string literal "Redraw", which is explicitly allowed in initializers of global and static variables.

I got in the habit of doing this back when initializer "type inference" was worse and noticed it while trying to compile a program of mine.

I'm not sure what you mean by this. C doesn't have any initializer type inference; you always have to specify the types of the objects you initialize.

~tekk REPORTED INVALID 1 year, 6 months ago

Register here or Log in to comment, or comment via email.