我正在尝试C++20 中引入的[[no_unique_address]]属性。据我从cppreference 文章和dcl.attr.nouniqueaddr标准章节中了解到,此属性表明该字段不需要具有与该类的所有其他非静态数据成员不同的地址。因此编译器可以优化结构体的内存布局。但有一件事让我感到困惑。
考虑以下示例(https://godbolt.org/z/fj6nGebcs):
struct Empty {};
struct Test {
[[no_unique_address]] Empty em1;
char f1;
int f2;
[[no_unique_address]] Empty em2;
};
Run Code Online (Sandbox Code Playgroud)
该字段em1的大小为零,并将位于与 相同的地址f1。对我来说,似乎合乎逻辑的是,可以应用相同的优化em2,并且它将具有相同的地址和f2零大小。但事实并非如此。经过一些实验,我可以说,如果[[no_unique_address]]在结构体末尾定义了一个字段,则这种优化根本不起作用。因此,使用最新版本的 gcc 和 clang 进行编译时, 的大小struct Test将为 12(1 字节char字段、3 字节对齐、4 字节int字段以及struct Empty大小为 1 字节和 3 字节对齐的字段)。
现在让我们em2向上移动(https://godbolt.org/z/Goz9Tj66K):
struct Empty {};
struct Test {
[[no_unique_address]] Empty em1;
char f1;
[[no_unique_address]] Empty em2;
int f2;
};
Run Code Online (Sandbox Code Playgroud)
进行此更改后, 的大小struct Test将为 8,并且em2字段将具有与 相同的地址f2。
我不明白为什么会这样。我在clang中找到了相同结构大小的测试。最新的 gcc 也以同样的方式工作。
但我不确定为什么编译器不能[[no_unique_address]]像第二个例子一样在上面的第一个例子中应用优化。有技术限制吗?还是和编译器内部实现有关?
的行为[[no_unique_address]]始终由编译器自行决定;它永远不需要做任何事情。编译器可以在所有情况下忽略它,在某些情况下尊重它,在其他情况下忽略它,或者始终尊重它。只要编译器不是随机执行的(即:它是一致的),它就可以做任何它想做的事情(在其他布局规则内)。
那么为什么它在一种情况下有效,而在另一种情况下却不起作用呢?因为这就是编译器供应商实现它的方式。
如果您想充分利用它,请让编译器最容易处理。不要多次使用相同的空类型(这限制了编译器的功能)。首先声明所有空字段。
或者,您必须跟踪编译器正在使用的 ABI 规则。Linux 上使用的Itanium ABI对no_unique_address.
| 归档时间: |
|
| 查看次数: |
652 次 |
| 最近记录: |