【问题标题】:call function in struct initialization在结构初始化中调用函数
【发布时间】:2018-11-24 01:16:25
【问题描述】:

考虑以下 sn-p:

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 }
    };
    ...
}

在结构初始化块内调用函数是否合法/可移植?

【问题讨论】:

  • 您的意思是一般情况下还是仅适用于您的 sn-p 中的自动变量?您的标准兼容编译器怎么说?你能指望什么?为什么?
  • 正如您所展示的那样[在gcc]下编译干净。但是,如果您将m 设为全局(文件范围变量),它将不是。编译器标记htonl错误:初始化元素不是常量。我相信大多数 C 编译器都会以类似的方式运行。 旁注: C++ 确实 允许在全局范围内执行此操作 [在您的示例中,它警告 ntonl 未签名而不是已签名 int c,但这很容易修复]

标签: c function struct


【解决方案1】:

是的,这是合法的,只要您正在初始化具有 自动 存储持续时间的对象(如您的示例中所示)。对于具有静态 storage 持续时间的对象是不合法的,因为此类对象在其初始化程序中只允许 constant 表达式。

还要记住,尽管在 C 中初始化表达式的求值是不确定的顺序。这意味着如果您的初始化程序中有多个函数调用,并且这些函数的结果取决于某些共享状态,则这些初始化程序的行为可能无法预测

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

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

关于可移植性,可以注意到 C89/90 不允许这样做(在 C89/90 中,所有 {}-enclosed 初始值设定项都必须是常量表达式,即使对于自动对象也是如此),但最流行的 C89/90编译器无论如何都支持这一点。

【讨论】:

    【解决方案2】:

    在结构初始化块内调用函数是否合法/可移植?

    Initialization (§6.7.8/1)

    [...]

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

    ~> 初始化器列表由初始化器组成

    Initialization (§6.7.8/4)

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

    ~> 初始化器由表达式组成。 (constant-expr. 用于具有静态存储持续时间的对象)

    Expressions (§6.5/1):

    表达式是一系列运算符和操作数,用于指定值的计算,或指定对象或函数,或产生副作用,或执行它们的组合。

    ~> 函数调用就是一个表达式。

    【讨论】:

    • @DavidC.Rankin 抱歉,您是什么意思?
    • 对不起,这是“加勒比海盗”中有趣的台词,符合“代码”的良好引用。
    • @DavidC.Rankin 哦,合法-代码。现在我懂了。是的,我本质上是一名律师;)
    猜你喜欢
    • 2020-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-17
    • 2015-08-08
    • 2020-08-31
    • 2013-04-01
    • 1970-01-01
    相关资源
    最近更新 更多