1

Is it possible to initialize a static array with a ternary operator in an initializer? For example:

// Array of functions 
static const Callback_t CallbackArray[] =
{
    GenConfig,
    GenInfo,
    /* here is the ternary operator to chose a callback */
    Test() ? Config : NULLConfig,   
};

where Test() is a function that returns a 0 or 1

// somewhere else in the code
int gVar = 0;

int TEST(void)
{
    return gVar;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
omer ido
  • 27
  • 5

3 Answers3

3

If the array does not have static storage duration then the operator can be used as an initializer expression.

From the C Standard (6.7.9 Initialization)

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

Take into account that you may not declare an array of functions but you may declare an array of pointers to functions.

Here is a demonstrative program

#include <stdio.h>

void f( void ) { puts( "f"); }
void g( void ) { puts( "g"); }

int main(void) 
{
    int x = 1, y = 2;

    void ( *fp[] )( void ) = { x < y ? f : g };

    fp[0]();

    return 0;
}

The program output is

f

If a function type is too complicated you can introduce a typedef for it. For example

#include <stdio.h>

void f( void ) { puts( "f"); }
void g( void ) { puts( "g"); }

int main(void) 
{
    int x = 1, y = 2;

    typedef void F( void );

    F * fp[] = { x < y ? f : g };

    fp[0]();

    return 0;
}

You can use the conditional operator to initialize an array with static storage duration. The problem is that the condition must be a constant expression that is not always suitable. For example

#include <stdio.h>

void f( void ) { puts( "f"); }
void g( void ) { puts( "g"); }

typedef void F( void );

F * fp[] = { 1 ? &f : &g };

int main(void) 
{
    fp[0]();

    return 0;
}

From the C Standard (6.6 Constant expressions)

9 An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type. The array-subscript [] and member-access . and -> operators, the address & and indirection * unary operators, and pointer casts may be used in the creation of an address constant, but the value of an object shall not be accessed by use of these operators.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Nothing in your examples has static storage duration though? Didn't you mean to declare the function pointer array at file scope? – Lundin Jan 19 '17 at 15:29
  • Okay that makes more sense since the OP seem to also have an array of function pointers with static storage duration. This shows that the conditional operator isn't a problem. – Lundin Jan 19 '17 at 15:32
2

The CallbackArray array has static storage duration (i.e. because of static keyword or it might have been placed outside any function), which implies, that it must be initialized with constant expressions.

Here, the conditional operator ?: does not yield constant expression (because it contains function call), hence the code is is invalid.

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • I don't believe this is correct. I can't find anything in 6.5.15 supporting your statement. Source? Also `static const int foo = 1 ? 1 : 0;` compiles just fine with `gcc -std=c11 -pedantic-errors`. – Lundin Jan 19 '17 at 15:26
  • @Lundin: I believe it is C11 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.`. – Grzegorz Szpetkowski Jan 19 '17 at 15:33
  • Yes but that doesnt prove that all operands and the result of the conditional operator cant be constant expressions. – Lundin Jan 19 '17 at 21:02
  • @Lundin: You are right with that, the original answer was incorrect. Neverthless, the key point is still valid. C11 6.6/3 says `Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is not evaluated.`. – Grzegorz Szpetkowski Jan 19 '17 at 21:15
0

You cannot initialize the contents of a static array based on a function.

But make another function to choose...

typedef returntype (*fxtype)(parmtypes);

fxtype choose(void) {
    return Test() ? Config : NULLConfig;
}

static const Callback_t CallbackArray[] =
{
    GenConfig,
    GenInfo,
    choose,   
};
pmg
  • 106,608
  • 13
  • 126
  • 198
  • 1
    Interesting idea, but to be a proper replacement, doesn't `choose()` have to call the correct function? That is, the intended code would use `(*CallbackArray[2])()` and expect the function to be called, so your substitute should be more like `return Test() ? Config() : NULLConfig();`? – Jonathan Leffler Jan 19 '17 at 18:31