请考虑以下代码:
#include <cstdint>
#include <bit>
#include <utility>
struct A { uint32_t a[100]; };
struct B { uint16_t b[200]; };
void test(const A&);
void foo() {
B tmp;
test(std::bit_cast<A>(std::move(tmp)));
}
void bar() {
B tmp;
test(reinterpret_cast<A&>(tmp));
}
对于带有-O3的clang 15,foo和bar是等效的,但是对于带有-O3的GCC 12.2,foo需要进行数据复制(rep movsq)。
foo():
sub rsp, 808
mov ecx, 50
lea rdi, [rsp+400]
mov rsi, rsp
rep movsq
lea rdi, [rsp+400]
call test(A const&)
add rsp, 808
ret
bar():
sub rsp, 408
mov rdi, rsp
call test(A const&)
add rsp, 408
ret
哪个编译器选项可以让GCC优化像Clang这样的东西?谢谢。Pidoss. -Ofast对这个问题没有帮助。
**[编辑]**根据user 17732522提供的答案,我将代码修改为:
#include <cstdint>
#include <bit>
struct A { uint32_t a[100]; };
struct B { uint16_t b[200]; };
void test(const A&);
void foo(B arg) {
test(std::bit_cast<A>(arg));
}
void bar(B arg) {
test(reinterpret_cast<A&>(arg));
}
现在GCC和Clang都使用foo的数据复制。所以,看起来std::bit_cast并不打算涵盖这种情况。
1条答案
按热度按时间mccptt671#
std::move
到std::bit_cast
是完全没有意义的,并且根本没有任何效果,因为std::bit_cast
具有左值引用参数,并且没有右值引用重载。在您的测试用例中,除了从
foo
中读取(未初始化!)数据外,tmp
从未在foo
中使用过。因此,很明显,编译器没有意识到这个对象根本不需要,而未初始化的A
可以直接使用,这是一个错过的优化。这不是您可以在语言级别上解决的问题。这完全取决于编译器优化。实际上,GCC似乎有意不删除复制指令,因为您正在阅读未初始化的数据。如果您在
B
中对数组进行零初始化,那么GCC会为两个函数生成相同的输出,而在std::bit_cast
版本中不需要额外的复制。对于这个问题,您确实没有什么可以做的,但是我在测试用例中确实没有看到任何价值。您可以直接声明一个
A
,并具有相同的效果。