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

Sam*_*tha 7 c c++ struct c11 c++20

是否可以使用聚合初始化使指针aptr指向a同一成员struct

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

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

问题是针对CC++

ana*_*ciu 8

一个工作初始化将是:

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

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

工作样本:

C11 GNU

C++2a GNU

关于初始化的正确性:

对于 C:

初始化列表表达式的计算相对于彼此是不确定的,因此任何副作用发生的顺序是不确定的。

对于 C++:

在花括号初始化器列表的初始化器列表中,初始化器子句,包括任何由包扩展([temp.variadic])产生的结果,按它们出现的顺序进行评估。也就是说,与给定的初始化子句相关联的每个值计算和副作用在与在初始化器列表的逗号分隔列表中跟随它的任何初始化子句相关联的每个值计算和副作用之前排序

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

所以这是对C和的正确初始化C++


这段代码需要注意的MSVC是,在 中,有一个编译错误C++

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

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

使用std:c++latest错误更改为:

use of designated initializers requires at least '/std:c++latest'
Run Code Online (Sandbox Code Playgroud)

然而,编译器,从范围clang 3.1clang 10.0gcc 4.9.0gcc 10.0C++03C++2a无警告编译罚款。

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

话虽如此,第二个解决方案是:

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

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

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

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