相关: Is this treatment of int64_t a GCC AND Clang bug?
我能想到的唯一解决方案是将其中一个操作数显式转换为int64
,强制该产品至少为int64
。
但如果以这种方式完成,那么它可以根据编译器的智能实际执行int64*int32
或int64*int64
,或理想情况下将其优化回{{1} }}
正如相关问题中所讨论的,将int32*int32
的结果分配给int32*int32
并不会改变int64
已经导致UB的事实。
有什么想法吗?
答案 0 :(得分:9)
您已经以标准,便携,高效的方式表明了如何做到这一点:
int64_t mul(int32_t x, int32_t y) {
return (int64_t)x * y;
// or static_cast<int64_t>(x) * y if you prefer not to use C-style casts
// or static_cast<int64_t>(x) * static_cast<int64_t>(y) if you don't want
// the integral promotion to remain implicit
}
您的问题似乎是关于假设的体系结构,其具有与功能签名相对应的汇编指令
int64_t intrinsic_mul(int32_t x, int32_t y);
int64_t intrinsic_mul(int64_t x, int64_t y);
int64_t intrinsic_mul(int64_t x, int32_t y); // and maybe this too
并且,在这个假设的体系结构中,第一个具有相关优势,而此外,编译器在编译上述函数时无法使用此指令,并且最重要的是,它失败了提供对上述内在的访问。
我希望这样的场景真的很少见,但是如果你真的发现自己处于这种情况,大多数编译器也允许你编写内联汇编,这样你就可以编写一个调用它的函数直接使用特殊指令,并且仍然提供足够的元数据,以便优化器可以有效地使用它(例如,使用符号输入和输出寄存器,以便优化器可以使用它想要的任何寄存器,而不是使寄存器选择硬编码。)
答案 1 :(得分:5)
内置算术表达式仅针对同类操作数类型退出。任何涉及混合类型的表达都意味着整数提升,并且算术操作本身只是为同类型定义并应用于同类型。
选择int32_t
或int64_t
。
正如您可能正确理解的那样,对于两种类型算术运算(至少+
,-
和*
)的选择都容易受到UB溢出的影响,但是不会有溢出在两个int64_t
上运行时,两者都可以表示为int32_t
s。例如,以下工作:
int64_t multiply(int32_t a, int32_t b)
{
// guaranteed not to overflow, and the result value is equal
// to the mathematical result of the operation
return static_cast<int64_t>(a) * static_cast<int64_t>(b);
}
作为示例,以下是GCC如何将其转换为Linux上的x86和x86_64(请注意不同的调用约定):
multiply(int, int):
// x86 (32-bit, "-m32 -march=i386") x86-64 ("-m64 -march=x86-64")
// args are on the stack args are in EDI, ESI
// return in EDX:EAX return in RAX
mov eax, DWORD PTR [esp+8] movsx rax, edi
movsx rsi, esi
imul DWORD PTR [esp+4] imul rax, rsi
ret ret