C中的移位运算符(<<,>>)是算术运算符还是逻辑运算符?

时间:2020-03-05 18:38:55  来源:igfitidea点击:

在C语言中,移位运算符(<<>>`)是算术运算符还是逻辑运算符?

解决方案

回答

左移时,算术移位和逻辑移位之间没有区别。向右移位时,移位的类型取决于要移位的值的类型。

(作为不熟悉该差异的读者的背景知识,"逻辑"右移1位会将所有位向右移,并用0填充最左边的位。"算术"移位将原始值保留在最左边。在处理负数时,差异变得很重要。)

移位无符号值时,C中的>>运算符是逻辑移位。移位有符号值时,>>运算符是算术移位。

例如,假设使用32位计算机:

signed int x1 = 5;
assert((x1 >> 1) == 2);
signed int x2 = -5;
assert((x2 >> 1) == -3);
unsigned int x3 = (unsigned int)-5;
assert((x3 >> 1) == 0x7FFFFFFD);

回答

根据K&R第二版,结果的实现取决于符号值的右移。

维基百科说C / C ++通常会对有符号值进行算术转换。

基本上,我们需要测试或者不依赖编译器。我对当前MS C ++编译器的VS2008帮助说,他们的编译器进行了算术转换。

回答

好吧,我在维基百科上查询了一下,他们的意思是:

C, however, has only one right shift
  operator, >>. Many C compilers choose
  which right shift to perform depending
  on what type of integer is being
  shifted; often signed integers are
  shifted using the arithmetic shift,
  and unsigned integers are shifted
  using the logical shift.

因此,听起来好像取决于编译器。同样在该文章中,请注意,算术和逻辑左移相同。我建议对边界情况(当然是高位设置)使用一些带符号和无符号的数字进行简单测试,然后查看编译器上的结果。我还建议避免依赖于一个或者另一个,因为C似乎没有标准,至少在合理且有可能避免这种依赖的情况下。

回答

就获得的移位类型而言,重要的是要移位的值的类型。错误的经典来源是将文字转换为例如掩盖位。例如,如果我们想删除无符号整数的最左位,则可以尝试将其用作掩码:

~0 >> 1

不幸的是,这会给我们带来麻烦,因为掩码将设置所有位,因为要移位的值(〜0)是带符号的,因此将执行算术移位。相反,我们希望通过将值明确声明为无符号值来强制进行逻辑转换,即通过执行以下操作:

~0U >> 1;

回答

gcc通常会在无符号变量上使用逻辑移位,而在有符号变量上使用左移位。算术右移是真正重要的一个,因为它将对变量进行符号扩展。

与其他编译器一样,gcc将在适用时使用此方法。

回答

以下是保证C中int的逻辑右移和算术右移的函数:

int logicalRightShift(int x, int n) {
    return (unsigned)x >> n;
}
int arithmeticRightShift(int x, int n) {
    if (x < 0 && n > 0)
        return x >> n | ~(~0U >> n);
    else
        return x >> n;
}