当 b 大于 a 中的位数时右移(a >> b)的未定义行为?

Undefined behaviour of right shift (a >> b) when b is greater than the number of bits in a?

本文关键字:gt 未定义 右移 大于      更新时间:2023-10-16

显然,右移操作的行为:

a >> b

b >= sizeof(a)*CHAR_BIT时,在C和C++中是未定义的(而在正常情况下,由于右移而从左边引入的"新位"等于零)。

为什么这种未定义的行为比b >= sizeof(a)*CHAR_BIT时将结果设置为零要好?

我们可以从"为什么语言设计者容忍未定义的行为"中了解到语言为什么选择未定义行为,它说:

这个答案来自C背后的两个通用设计原则:

  1. 该语言不应给实现带来不必要的开销
  2. 在各种各样的硬件上实现C应该尽可能容易

在这种特定的情况下,当我们使用大于位宽的移位计数时会发生什么将取决于体系结构,例如,正如我在这里的回答中所解释的:

在某些平台上,移位计数将被屏蔽5 bits。例如,在x86体系结构上,我们可以在IA-32体系结构兼容性部分中的"英特尔®;64和IA-32体系结构软件开发人员手册"部分看到SAL/SAR/SHL/SHR--移位,内容是:

8086不屏蔽移位计数。但是,所有其他IA-32处理器(从英特尔286处理器开始)都会将移位计数屏蔽为5位,从而导致最大计数为31。[…]

因此,在某些平台上,为任意计数实现移位可能会带来负担,因此最好将其保留为未定义的行为。

为什么不指定行为

如果我们看一下国际标准——程序设计语言——C的基本原理,它说:

未指定的行为使实现者在翻译程序时有一定的自由度。这个纬度然而,并没有延伸到无法翻译程序的程度,因为所有可能的行为是"正确的",因为它们不会在任何实现中导致未定义的行为。

因此,一定存在或仍然存在行为不正确的情况,并且会出现严重问题。

为什么这种未定义的行为比将结果设置为零更好的示例。

通常,一个CPU只有一条指令来执行移位。如果该指令需要与上限进行比较,则需要更多的电路并减缓移位。相反,许多CPU只是使用移位的最低有效位来确定要移位多少。

// Example - not specified behavior  (assume 32-bit int)
y = 1 << 34;
// same as 
y = 1 << 2;

第一批PC使用8/16位处理器,该处理器使用最少的8位来确定移位,因此一旦移位计数大于"int宽度",但小于256,它确实会移位为零。这样做的问题是,每班需要1个时钟刻度。因此,在最坏的情况下,简单的移位命令可能需要255个时钟信号才能执行。当然,在16次滴答声之后,除了0之外什么都没有移动。此最坏情况指令不可中断!因此,使该处理器的最坏情况中断延迟远比竞争对手差。英特尔没有再犯这个错误。