【问题标题】:Is it possible to leave fields unitialized using designated intiailizers?是否可以使用指定的初始化器将字段单元化?
【发布时间】:2020-07-27 19:47:43
【问题描述】:

考虑以下结构和函数来创建结构:

#define MAX_ELEMS 1000

struct stuff {
  double magic;
  bool is_valid[MAX_ELEMS];
  double values[MAX_ELEMS];
};

struct stuff make_stuff(double magic) {
    return (struct stuff){
        .magic = magic
    };
}

就我而言,我需要将stuff.magic 初始化为给定值,并将stuff.is_valid 数组初始化为零,但我不想初始化stuff.values(因为它们由stuff.is_valid 保护并稍后按需初始化)。

我可以使用指定的初始化器来实现这一点吗?

我知道我可以在没有的情况下实现它,但这更丑陋且更容易出错(除其他原因外,我现在需要将 stuff.is_valid 显式归零,可能需要使用 memset)。

【问题讨论】:

    标签: c performance c99 micro-optimization designated-initializer


    【解决方案1】:

    任何未特别初始化的字段都将用零填充。

    所以,不,如果你初始化任何字段,它们都会得到一些东西(即使它只是零)

    【讨论】:

      【解决方案2】:

      只能通过“正常”的赋值和memset来完成。

      struct stuff make_stuff(double magic) 
      {  
          struct stuff s;
          memset(s.is_valid, 0, sizeof(s.is_valid));
          s.magic = magic;
          return s;
      } 
      

      但是,如果您正在寻找返回如此大的结构的效率,那将毫无意义,因为当结构按值传递时,我会完整复制两次

      最好将指针传递给结构体。

      struct stuff *make_stuff(struct stuff *s, double magic) 
      {  
          memset(s -> is_valid, 0, sizeof(s -> is_valid));
          s -> magic = magic;
          return s;
      } 
      

      【讨论】:

      • 只要make_stuff可以内联,按值返回就可以了。那么这是编写可用于struct stuff foo = make_stuff(1.0); 的包装器的好方法。
      • @PeterCordes - 内联并不总是必要的,至少对于合理的 ABI。调用者会传递一个指向返回值区域的指针,调用者会直接填写返回值,不需要在调用者中进行复制。这种“优化”甚至发生在-O0 for clang and gcc。诚然,正如caller2 所说明的那样,它并非在所有情况下都有效(我相信这在 C++ 中有效,它有额外的语言使它成为可能)。
      • @BeeOnRope:嗯,内联也并不总是足够的。 godbolt.org/z/5h1cE4 表明使用 1.0 而不是 0. 的 arg,gcc 错过了优化并且仍然执行 9008 字节的 memcpy,而 clang 没有。因此,显式获取输出参数,而不是通过调用约定隐式获取,显然更安全。
      • @PeterCordes - 这当然很奇怪。无论如何,我的用法是struct stuff s = make(...) 的形式,即分配给一个新定义的对象,这似乎不太成问题。
      • @PeterCordes 示例的琐碎性使得内联成为可能。
      猜你喜欢
      • 2017-09-06
      • 1970-01-01
      • 2020-11-13
      • 2016-03-03
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多