C中的位移

如果对应于有符号整数的位模式向右移位

1 vacant bit will be filled by the sign bit 2 vacant bit will be filled by 0 3 The outcome is implementation dependent 4 none of the above 

这个问题的答案是第三种选择..任何人都能解释一下这个问题,

还给出了一些基本思想,关于C编程中左移和右移算子背后的理论。 例如

当执行任何操作时,空位上填充的内容。 我检查并注意到左移将空位填充0并且右移填充1.请清除逻辑…

C不保证有符号位,或者有关整数的位级表示的任何信息,这就是原因。

对于二进制补码 ,您通常会看到符号位被移入,但这取决于实现。

我必须检查规范是否与实现有关。 但是,我在(mumble)多年的嵌入式系统项目中使用的每个实现都是明智的:

  • 左移位总是在低位移位0。 没有其他价值是有道理的。

  • 右移取决于数据类型。 有符号整数的右移将高位移位,因为它将其余的移位到右侧。 这被称为“算术移位”,并且具有良好的属性(至少在二进制补码算法中),它将值除以2,同时保留原始数字的符号。

    无符号整数的右移将0移位到高位,通常称为“逻辑移位”。

一个实现提供两种移位是有意义的,因为它们都很有用,并且使用signed / unsigned来选择哪个是合理的选择。

编辑:至少有一件绝对是依赖于实现的事情是C标准没有(完全)指定整数及其存储的底层实现。 例如,可以为使用一个补码算法的机器构建一个兼容的C编译器。 (我认为)也可以为一台机器构建一个兼容的编译器,该机器的本机存储是BCD大小。 (不,我错了,见下文。)

在实践中,世界几乎已经确定了CPU的两个补码二进制数,并且一些迂腐的问题得到了提升。

因此,问题的一部分实际上是:无论使用何种基础算术系统,如何以稳定的方式定义<<和>>运算符的含义。

IIRC, n<<1的定义实际上是n*2n>>1实际上是n/2 ,自然扩展到移位超过1(但不超过31 ......那里有未定义的龙......)并且认为如果在有符号值上操作, >>运算符将保留符号。

编辑2: Pete Kirkham在他的回答中指出,C标准确实特别禁止BCD表示整数的可怕情况,无论是有符号大小还是十进制补码。 我确信这是一件好事,即使Knuth在早期版本的“计算机编程艺术”中使用了(可选的)BCD机器作为他的示例代码。

在那些BCD是正确答案的罕见用例中,然后将它们存储在无符号长(8位十进制补码)或无符号64位整数(16位十进制补码或15位加号和标志的空间)中并使用精心设计的算术库来操纵它们是有道理的。

当然,在实践中,C实现将操作符直接映射到标准允许的CPU本机指令。 编写标准的人非常注意存在许多方法来实现甚至简单的事情,例如整数值的表示,而C标准反映了通过允许足够的实现定义的行为来让运算符在每个中有效地实现机。

替代方案迅速进入一个完全指定所有数学运算的世界,并且无法在任何机器上有效实施。

ISO C99在表示中需要一个符号位,但在各种补码/符号和幅度方案之间提供选项并允许填充位,所有这些都会影响>>的操作。

第6.2.6.2节(整数类型)

对于有符号整数类型,对象表示的位应分为三组:值位,填充位和符号位。 不需要任何填充位; 应该只有一个符号位。

第6.5.7节(按位移位运算符)

E1 >> E2的结果是E1右移E2位的位置。 如果E1具有无符号类型或者E1具有有符号类型和非负值,则结果的值是E1 / 2 E2的商的整数部分。 如果E1具有带符号类型和负值,则结果值是实现定义的。

它没有指定使用1的恭维,2的恭维或符号和幅度中的哪一个,也没有指定符号位是值位的左侧还是右侧,或者填充的位置,所有这些都会影响>>的输出。签署否定的运营商。

在回答RBerteig的查询时,C99排除了整数的BCD表示:

第6.2.6.2节(整数类型)

如果有N个值位,则每个位应表示1和2 N -1之间的2的不同幂,因此该类型的对象应能够使用纯二进制表示来表示0到2 N-1的值; 这应该被称为价值表示。

C语言实现倾向于将位移操作直接映射到相应的机器代码指令上。 由于不同的硬件体系结构在历史上做了不同的事情,因此C规范倾向于保留实现定义,以便C实现可以利用硬件提供的任何function。

结果取决于实施。 但是,在实践中,我曾经使用的每个x86,PPC和MIPS编译器都遵循此规则进行右移:

  1. 如果操作数是有符号整数,则空位用符号位填充(实际上是最高位)

  2. 如果操作数是无符号整数,则空位填充为零。

正如RBerteig所说,对于有符号整数,n >> 1 = n / 2( 向下舍入)表示正n和负n,对于无符号整数,n >> 1 = n / 2,即使n> 2 ^ 31(在32位架构上)。

相应的硬件指令是算术(符号扩展)和逻辑(不符号扩展)移位; 编译器根据操作数是有符号还是无符号在它们之间进行选择。