#include <cstdint>
uint64_t hr1(const uint64_t x, const bool a, const int n) noexcept
{
if (a) {
return x | (a << n);
}
return x;
}
uint64_t hr2(const uint64_t x, const bool a, const int n)
{
return x | ((a ? 1ull : 0) << n);
}
hr1(unsigned long, bool, int):
mov rax, rdi
test sil, sil
jne .L4
ret
.L4:
mov ecx, edx
mov esi, 1
sal esi, cl
movsx rsi, esi
or rax, rsi
ret
hr2(unsigned long, bool, int):
mov ecx, edx
movzx esi, sil
sal rsi, cl
mov rax, rsi
or rax, rdi
ret
为什么clang和gcc无法将第一个功能优化为第二个功能?
这些功能没有相同的行为。特别是在第一个中,a
将经历整数提升为int
中的a << n
,因此如果n >= std::numeric_limits<int>::digits
(通常为31),则移位将具有不确定的行为。
[在第二个函数中不是这样,其中a ? 1ull : 0
将导致产生unsigned long long
的通用类型,因此该移位将为所有值n < std::numeric_limits<unsigned long long>::digits
(通常为64)定义了明确定义的行为可能大于std::numeric_limits<int>::digits
(通常为31)。
您应在两个移位中都将a
和1
强制转换为uint64_t
,以使代码在所有明智的输入(即n < 64
)中表现良好。
这些功能没有相同的行为。特别是在第一个a
中,整数将升为int
中的a << n
,因此,如果n >= std::numeric_limits<int>::digits
,则该函数将具有未定义的行为。
[在第二个函数中不是这种情况,它将对所有可能大于n < std::numeric_limits<unsigned long long>::digits
(通常为32)的值n >= std::numeric_limits<int>::digits
(通常为64)具有明确定义的行为。