聚合初始化,将成员指针设置为相同的结构成员

Aggregate initialization, set member pointer to same struct member

是否可以使用聚合初始化使指针 aptr 指向 a,后者是同一个 struct 的成员?

struct S {
  int a;
  int* aptr;
};

int main() {
  S s = {
    .a = 3,
    .aptr = &a //point aptr to a
  };
  return 0;
}

问题针对 CC++

工作初始化为:

struct S {
  int a;
  int* aptr;
};

int main() {
    struct S s = {.a = 3, .aptr = &s.a};
    printf("%d", *s.aptr);
}

工作样本:

C11 GNU

C++2a GNU

关于初始化的正确性:

对于 C:

The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified.

对于 C++:

Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions ([temp.variadic]), are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list.

然而,尽管我们可以观察到差异,但在这种情况下,表达式求值的顺序似乎并不重要,因为您实际上并没有访问 s.a 的值,只是访问它的地址此时可以访问。

所以这是 CC++.

的正确初始化

这段代码需要注意的地方,在MSVC中,在C++中存在编译错误:

use of designated initializers requires at least '/std:c++latest'

使用std:c++latest错误变为:

designated and non-designated initializers is nonstandard in C++

但是,从 clang 3.1clang 10.0gcc 4.9.0gcc 10.0C++03C++2a 编译正常,没有警告。

C++20中引入的指定初始化器,所以不接受它们实际上是正确的,因为MSVC仍然不接受/std:c++20,它是还不能使用它们,看起来 gccclang 总是提供对这些初始化程序的支持。

也就是说,第二种解决方案是:

struct S {
    int a;
    int* aptr;
};

int main() {
    struct S s = { 3, &s.a };
    printf("%d", *s.aptr);
}

第二个版本的初始化在每个测试的编译器中都没有问题,因此可以假设它更便携。

第一个版本可能更易于阅读,并且更容易识别初始化中的错误,这是指定初始化器的优点之一。