是否可以在初始化程序中使用三元运算符初始化静态数组?

Posted

技术标签:

【中文标题】是否可以在初始化程序中使用三元运算符初始化静态数组?【英文标题】:Is it possible to initialize a static array using a ternary operator in an initializer? 【发布时间】:2017-06-04 08:25:19 【问题描述】:

例如:

// Array of functions 
static const Callback_t CallbackArray[] =

    GenConfig,
    GenInfo,
    /* here is the ternary operator to chose a callback */
    Test() ? Config : NULLConfig,   
;

其中 Test() 是一个返回 0 或 1 的函数

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

int TEST(void)

    return gVar;

【问题讨论】:

是的。这是完全有效的。只要Test() 是一个宏 尝试过吗?它奏效了吗?如果没有,您遇到了什么错误? 我认为这里唯一的问题是Test(),因为函数不是常量表达式。如果不是这样,代码应该没问题。 Test() 是一个函数,正如我所写的,而不是宏。它似乎有效,但我不明白如何,因为 Test() 检查全局变量 在初始化中,代码使用Test()。有一个函数叫做TEST()TEST()Test() 不同。发布 true 代码。目前还不清楚要问什么。 【参考方案1】:

如果数组没有静态存储持续时间,则运算符可以用作初始化表达式。

来自 C 标准(6.7.9 初始化)

4 具有静态的对象的初始化程序中的所有表达式 或线程存储持续时间应为常量表达式或字符串 文字。

考虑到你不能声明一个函数数组,但你可以声明一个函数指针数组。

这是一个演示程序

#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;

程序输出是

f

如果一个函数类型太复杂,你可以为它引入一个 typedef。例如

#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;

您可以使用条件运算符来初始化具有静态存储持续时间的数组。问题是条件必须是一个并不总是合适的常量表达式。例如

#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;

来自 C 标准(6.6 常量表达式)

9 地址常量是一个空指针,一个指向左值的指针 指定静态存储持续时间的对象,或指向 a 的指针 功能指示符; 应使用显式创建 一元 & 运算符 或转换为指针类型的整数常量,或 通过使用数组或函数类型的表达式隐含地。这 数组下标 [] 和成员访问。和 -> 运算符,地址 & 和间接 * 一元运算符和指针转换可用于 创建地址常量,但对象的值应 不能使用这些运算符访问。

【讨论】:

您的示例中没有任何内容具有静态存储持续时间吗?你不是要在文件范围内声明函数指针数组吗? 好吧,这更有意义,因为 OP 似乎也有一个具有静态存储持续时间的函数指针数组。这说明条件运算符没有问题。【参考方案2】:

CallbackArray 数组具有静态存储持续时间(即由于 static 关键字或者它可能已放置在任何函数之外),这意味着它必须使用常量表达式进行初始化。

这里条件运算符?:不产生常量表达式(因为它包含函数调用),因此代码无效。

【讨论】:

我不相信这是正确的。我在 6.5.15 中找不到任何支持您的陈述的内容。资源? static const int foo = 1 ? 1 : 0; 也可以与 gcc -std=c11 -pedantic-errors 一起编译。 @Lundin:我相信是 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. 是的,但这并不能证明所有操作数和条件运算符的结果都不能是常量表达式。 @Lundin:你说得对,原来的答案不正确。尽管如此,关键点仍然有效。 C11 6.6/3 说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.【参考方案3】:

您不能初始化基于函数的static 数组的内容。

但要选择另一个功能...

typedef returntype (*fxtype)(parmtypes);

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


static const Callback_t CallbackArray[] =

    GenConfig,
    GenInfo,
    choose,   
;

【讨论】:

有趣的想法,但要成为适当的替代品,choose() 不是必须调用正确的函数吗?也就是说,预期的代码将使用(*CallbackArray[2])() 并期望调用该函数,因此您的替代代码应该更像return Test() ? Config() : NULLConfig();?

以上是关于是否可以在初始化程序中使用三元运算符初始化静态数组?的主要内容,如果未能解决你的问题,请参考以下文章

在三元运算符中初始化捕获 lambda

如何使用三元运算符有条件地初始化 const char* arr[]

数组容量的动态初始化

第十二章 类和动态内存分配

提高代码效率的 20 个JavaScript 技巧和窍门

提高代码效率的 20 个JavaScript 技巧和窍门