2

Consider the following snippet:

struct my_struct {
     int a;
     int b;
     int c;
};


void my_func(unsigned long x)
{
    struct my_struct m[] = {
         { 0, 1, 2 },
         { 11, 22, htonl(x) },
         { 0x1, 0xa, 0xbb }
    };
    ...
}

Is it legal/portable to call a function inside of a structure initialization block?

2
  • Do you mean in general or just for automatic variables as in your snippet? What does your standard compliant compiler say? What do you expect? Why? Commented Nov 24, 2018 at 1:39
  • This compiles cleanly [under gcc] as you've presented it. However, if you made m a global (file scope variable), it will not. The compiler flags htonl: error: initializer element is not constant. I believe most C compilers will behave in a similar manner. Side note: C++ does allow this at global scope [in your example, it warns about ntonl being unsigned vs the signed int c, but this would be easy enough to fix] Commented Nov 24, 2018 at 1:52

2 Answers 2

5

Yes, it is legal, as long as you are initializing an object with automatic storage duration (as in your example). For objects with static storage duration that would not be legal, since such objects allow only constant expressions in their initializers.

Also keep in mind though that in C evaluations of initializer expressions are indeterminately sequenced with respect to one another. Which means that if you have multiple function calls among your initializers and these functions' results depend on some shared state, these initalizers might behave unpredictably

int foo()
{
  static int a;
  return ++a;
}

int main()
{
  struct { int x, y; } s = { foo(), foo() };
  /* Can be `{ 1, 2 }` or `{ 2, 1 }`... */
}

With regard to portability, one can note that C89/90 did not permit this (formally in C89/90 all {}-enclosed initializers has to be constant expressions, even for automatic objects), but most popular C89/90 compilers supported this regardless.

Sign up to request clarification or add additional context in comments.

Comments

4

Is it legal/portable to call a function inside of a structure initialization block?

Initialization (§6.7.8/1)

[...]

|     initializer-list:
|             designationopt initializer
|             initializer-list , designationopt initializer

~> initializer-lists consist of initializers

Initialization (§6.7.8/4)

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

~> Initializers consist of expressions. (constant-expr. for objects with static storage duration)

Expressions (§6.5/1):

An expression is a sequence of operators and operands that specifies computation of a value, or that designates an object or a function, or that generates side effects, or that performs a combination thereof.

~> A function call is an expression.

3 Comments

@DavidC.Rankin Sorry, what do you mean?
Sorry, that's the funny line for "Pirates of the Caribbean" that fit with the good cites to the "code".
@DavidC.Rankin oh, legal-code. Now I get it. Yes, I'm a lawyer at heart ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.