如果对应于有符号整数的位模式向右移动,则
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.请清除逻辑......
答案 0 :(得分:5)
C不保证有一个符号位,或者有关整数的位级表示的任何信息,这就是原因。
对于two's complement,您通常会看到符号位被移入,但这取决于实现。
答案 1 :(得分:5)
我必须检查规范,了解具体依赖于实现的问题。 但是,我在(mumble)多年的嵌入式系统项目中使用的每个实现都是明智的:
左移始终在低位移位0。没有其他价值是有道理的。
右移取决于数据类型。有符号整数的右移将高位移位,因为它将其余的移位到右侧。这被称为“算术移位”,并且具有良好的属性(至少在二进制补码运算中),它将值除以2,同时保留原始数字的符号。
无符号整数的右移将0移位到高位,通常称为“逻辑移位”。
实现提供两种转换是有意义的,因为它们都很有用,并且使用signed / unsigned来选择哪一个是明智的选择。
编辑:至少有一件绝对是依赖于实现的事情是C标准没有(完全)指定整数及其存储的底层实现。例如,可以为使用一个补码算法的机器构建一个兼容的C编译器。 (我认为)也可以为一台机器构建一个兼容的编译器,该机器的本机存储器是标记为BCD的。 (不,我错了,见下文。)
在实践中,世界几乎已经确定了CPU的两个补码二进制数,并且一些迂腐的人被提出来了。
所以问题的一部分确实是:你如何定义<<<<和>>无论使用何种基础算术系统,运算符都是稳定的。
IIRC,n<<1
的定义实际上是n*2
,n>>1
实际上是n/2
,自然延伸超过1(但不超过1) 31 ......那里有未定义的龙......)以及>>
运算符如果在有符号值上运行则会保留符号的概念。
编辑2: Pete Kirkham在他的回答中指出,C标准明确禁止BCD表示整数的可怕情况,无论是有符号大小还是十进制补码。我确信这是件好事,即使Knuth在早期版本的The Art of Computer Programming中使用(可选)BCD机器作为他的示例代码。
在那些BCD是正确答案的罕见用例中,然后将它们存储在无符号长(8位十进制补码)或无符号64位整数(16位十进制补码或15位加号和标志的空间)中并使用精心设计的算术库来操纵它们是有道理的。
实际上,当然,C实现将操作符直接映射到标准允许的CPU本机指令。编写标准的人是非常注意到存在许多方法来实现甚至简单的事情,比如表示整数值,C标准通过允许足够的实现定义的行为来反映让操作员在每台机器上高效实施。
替代方案迅速进入一个完全指定所有数学运算的世界,并且无法在任何机器上有效实施。
答案 2 :(得分:2)
ISO C99在表示中需要一个符号位,但在各种恭维/符号和幅度方案之间提供选项并允许填充位,所有这些都会影响>>
的操作。
第6.2.6.2节(整数类型)
对于有符号整数类型,对象表示的位应分为三组:值位,填充位和符号 位。不需要任何填充位;应该只有一个 标志位。
和
第6.5.7节(按位移位运算符)
E1&gt;的结果&gt; 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的值 表示;这应该被称为价值表示。
答案 3 :(得分:0)
C语言实现倾向于将位移操作直接映射到相应的机器代码指令上。由于不同的硬件架构在历史上做了不同的事情,因此C规范倾向于保留实现定义,以便C实现可以利用硬件提供的任何东西。
答案 4 :(得分:0)
结果取决于实施。但是,实际上,我曾经使用过的每一个x86,PPC和MIPS编译器都遵循这个规则进行右移:
如果操作数是有符号整数, 空位充满了 标志位(真的是最多的 重要的一点)
如果操作数是 无符号整数,空位 充满了零。
正如RBerteig所说,这是为了签名整数,n&gt;&gt;对于正和负n,1 = n / 2(舍入 down ),对于无符号整数,n&gt;&gt;即使n> 1,1 = n / 2; 2 ^ 31(在32位架构上)。
相应的硬件指令是算术(符号扩展)和逻辑(不符号扩展)移位;编译器根据操作数是有符号还是无符号在它们之间进行选择。