[英]Undefined behaviour of right shift (a >> b) when b is greater than the number of bits in a?
显然,右移操作的行为:
a >> b
当b >= sizeof(a)*CHAR_BIT
时,在C和C ++中未定义(而在正常情况下,由于右移而从左侧引入的“新位”等于零)。
当b >= sizeof(a)*CHAR_BIT
时,为什么这种未定义的行为比将结果设置为零更好?
我们可以从为什么语言设计师容忍未定义的行为中选择未定义的行为来理解为什么语言会说:
这个答案来自C背后的两个一般设计原则:
- 该语言不应对实现施加任何不必要的开销。
- 在各种硬件上实现C应该尽可能简单。
在这种特定情况下,当我们使用大于位宽的移位计数时会发生什么情况将取决于架构,例如我在这里的答案中解释:
在某些平台上,移位计数将被屏蔽为5 bits
,例如在x86
架构上我们可以看到IA-32架构兼容性中的英特尔®64和IA-32架构软件开发人员手册部分SAL / SAR / SHL / SHR-Shift部分说:
8086不掩盖班次计数。 但是,所有其他IA-32处理器(从Intel 286处理器开始)确实将移位计数屏蔽为5位,最大计数为31. [...]
因此,在某些平台上实现任意计数的转移可能会很麻烦,因此最好不要使用不确定的行为。
为什么不指定未指明的行为
未指定的行为使实现者在翻译程序时具有一定的自由度。 然而,这个范围没有扩展到未能翻译程序,因为所有可能的行为都是“正确的”,因为它们在任何实现中都不会导致未定义的行为。
因此,一定存在案例或者仍然存在行为不正确并且会出现问题的情况。
举例说明为什么这种未定义的行为比将结果设置为零更好。
通常,CPU具有执行转换的单个指令。 如果需要该指令与上限进行比较,则需要更多电路并减慢移位。 相反,许多CPU只是使用转换的最低有效位来确定转移多少。
// Example - not specified behavior (assume 32-bit int)
y = 1 << 34;
// same as
y = 1 << 2;
第一台PC使用8/16位处理器,使用最少8位来确定移位,因此一旦移位计数大于`int width但小于256,它确实会以零移位。这个问题是每个班次花了1个时钟。 因此,在最坏的情况下,简单的移位命令可能需要255个时钟周期才能执行。 当然,在16个滴答之后,只有0被移动。 这个长期最坏情况的指令是不可中断的! 因此,使处理器的最坏情况中断延迟远远比竞争对手差。 英特尔没有再犯这个错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.