【发布时间】:2020-05-28 03:32:03
【问题描述】:
是否可以使用聚合初始化来使指针aptr 指向a,它是同一个struct 的成员?
struct S {
int a;
int* aptr;
};
int main() {
S s = {
.a = 3,
.aptr = &a //point aptr to a
};
return 0;
}
C 和 C++ 都有这个问题。
【问题讨论】:
是否可以使用聚合初始化来使指针aptr 指向a,它是同一个struct 的成员?
struct S {
int a;
int* aptr;
};
int main() {
S s = {
.a = 3,
.aptr = &a //point aptr to a
};
return 0;
}
C 和 C++ 都有这个问题。
【问题讨论】:
一个有效的初始化将是:
struct S {
int a;
int* aptr;
};
int main() {
struct S s = {.a = 3, .aptr = &s.a};
printf("%d", *s.aptr);
}
工作样本:
关于初始化的正确性:
对于 C:
初始化列表表达式的计算相对于彼此的顺序是不确定的,因此任何副作用发生的顺序都是未指定的。
对于 C++:
在花括号初始化列表的初始化器列表中,初始化器子句,包括任何由包扩展 ([temp.variadic]) 产生的子句,按照它们出现的顺序进行评估 . 也就是说,与给定初始值设定项子句相关的每个值计算和副作用都先于与在初始值设定项列表的逗号分隔列表中的任何初始值项子句相关的每个值计算和副作用进行排序强>.
但是,尽管我们可以观察到差异,但在这种情况下,计算表达式的顺序似乎并不重要,因为您实际上并没有访问 s.a 的值,只是访问它的地址点。
所以这对于 C 和 C++ 都是正确的初始化。
这段代码需要注意的一点,在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.1 到 clang 10.0 和 gcc 4.9.0 到 gcc 10.0 strong> 与 C++03 到 C++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);
}
第二个版本的初始化编译在每个测试的编译器中都没有问题,因此可以假设它更具可移植性。
第一个版本可能更易于阅读,并且可以更轻松地识别初始化中的错误,这是指定初始化程序的优点之一。
【讨论】: