【发布时间】:2011-10-02 05:29:35
【问题描述】:
获取一个 C++ 整数变量 i,并假设您将其值乘以 2。
如果i 有符号,我相信这个操作在某种程度上是等价的,至少在数学上,到:
i = i << 1;
但是如果i的类型是无符号的,那么由于无符号值不会溢出而是对其范围取模,大概操作是这样的:
i = (i << 1) & (decltype(i))-1;
现在,我认为实际的机器指令可能比乘法移位序列更简洁。但是现代的,比如 x86,CPU 会有无符号/模数学的特定指令吗?或者,与使用有符号值进行数学运算相比,使用无符号值进行数学运算是否会花费额外的指令?
(是的,在编程时关心这个是很荒谬的;我只是出于好奇而感兴趣。)
【问题讨论】:
-
由于
(decltype(i))-1(最好写成static_cast<decltype(i)>(-1)或~static_cast<decltype(i)>(0))全为1,因此与&一起使用是无操作的,可以被优化器删除。 -
为什么左移会导致下溢?另外,“无符号值 [...] 以它们的范围为模执行”这句话是什么意思?
-
@Mike:不一定。考虑
i是否具有类型unsigned short(16 位),但int是 32 位。那么i << 1是一个32位的值,而(decltype(i))-1是0xFFFF,即使在&被提升为int之后。在那种情况下,Tomalak 说标准需要掩码是错误的,但如果你这样做,掩码会产生影响。 结合将它分配回 i,但是,它没有任何效果,因为它只影响将被转换丢弃的位。 -
@Steve:等一下。您是说
<<的结果类型取决于 right 手边参数的类型,而不仅仅是 left 手边参数的类型?请链接到标准的相关部分,因为这是与几乎所有架构都不同的行为。 -
@Mike: 5.8/1,“操作数应为整数或枚举类型,并执行整数提升。结果的类型是提升的左操作数的类型”。积分提升在 4.5 中定义,如果
int可以表示unsigned short的每个值(在我的示例中它可以),则unsigned short提升为int,否则提升为unsigned int。 RHS的类型与它无关。