首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >什么是按位移位(bit- shift )运算符?它们是如何工作的?

什么是按位移位(bit- shift )运算符?它们是如何工作的?
EN

Stack Overflow用户
提问于 2008-09-26 19:47:15
回答 9查看 765.5K关注 0票数 1.5K

我一直在尝试在业余时间学习C语言和其他语言(C#、Java等)。具有相同的概念(并且经常使用相同的运算符) ...

我想知道的是,在核心级别,位移位(<<>>>>>)做了什么,它能帮助解决什么问题,以及在弯道周围潜伏着什么陷阱?换句话说,这绝对是位移位的入门级指南。

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2008-09-26 20:46:40

位移位运算符的作用正如其名称所暗示的那样。它们会移动比特。下面是对不同移位运算符的简要介绍。

运算符

  • >>是算术(或有符号)右移位operator.
  • >>>是逻辑(或无符号)右移位operator.
  • <<是左移位运算符,同时满足逻辑和算术移位的需要。

所有这些运算符都可以应用于整数值(intlong,可能还有shortbytechar)。在某些语言中,对任何小于int的数据类型应用移位运算符都会自动将操作数调整为int

请注意,<<<不是运算符,因为它是多余的。

还要注意,C和C++不区分右移位运算符。它们只提供>>运算符,右移行为是为带符号类型定义的实现。答案的其余部分使用C# / Java操作符。

(在所有主流的C和C++实现中,包括GCC和Clang/LLVM,有符号类型上的>>是算术。一些代码假设了这一点,但这并不是标准所保证的。然而,它并不是未定义的;标准要求实现以某种方式定义它。但是,负号数字的左移是未定义的行为(带符号整数溢出)。因此,除非您需要算术右移,否则使用无符号类型进行位移位通常是个好主意。)

左移(<<)

整数以一系列位的形式存储在内存中。例如,存储为32位int的数字6将为:

代码语言:javascript
复制
00000000 00000000 00000000 00000110

将此位模式左移一个位置(6 << 1)将产生数字12:

代码语言:javascript
复制
00000000 00000000 00000000 00001100

正如您所看到的,数字向左移动了一个位置,右侧的最后一个数字用零填充。您可能还注意到,左移相当于乘以2的幂。因此,6 << 1等同于6 * 26 << 3等同于6 * 8。一个好的优化编译器会在可能的情况下用移位替换乘法。

非循环移位

请注意,这些不是循环移位。将该值向左移动一个位置(3,758,096,384 << 1):

代码语言:javascript
复制
11100000 00000000 00000000 00000000

结果为3,221,225,472:

代码语言:javascript
复制
11000000 00000000 00000000 00000000

移位到“末尾”的数字会丢失。它不会缠绕。

逻辑右移(>>>)

合乎逻辑的右移与左移相反。它们不是向左移动位,而是简单地向右移动。例如,将数字12移位:

代码语言:javascript
复制
00000000 00000000 00000000 00001100

向右移动一个位置(12 >>> 1)将返回原来的6:

代码语言:javascript
复制
00000000 00000000 00000000 00000110

所以我们可以看到,向右移动等同于除以2的幂。

丢失的比特消失了

然而,移位不能回收“丢失”的位。例如,如果我们改变这个模式:

代码语言:javascript
复制
00111000 00000000 00000000 00000110

在左边的4个位置(939,524,102 << 4),我们得到2,147,483,744:

代码语言:javascript
复制
10000000 00000000 00000000 01100000

然后移回((939,524,102 << 4) >>> 4),我们得到134,217,734:

代码语言:javascript
复制
00001000 00000000 00000000 00000110

一旦我们丢失了比特,我们就无法找回原来的价值。

算术右移(>>)

算术右移位与逻辑右移位完全相同,不同之处在于它不是用零填充,而是用最高有效位填充。这是因为最高有效位是符号位,即区分正数和负数的位。通过填充最高有效位,算术右移是符号保留的。

例如,如果我们将此位模式解释为负数:

代码语言:javascript
复制
10000000 00000000 00000000 01100000

我们的数字是-2,147,483,552。用算术移位将其右移4个位置(-2,147,483,552 >> 4)将得到:

代码语言:javascript
复制
11111000 00000000 00000000 00000110

或者数字134,217,722。

所以我们看到,我们通过使用算术右移,而不是逻辑右移,保留了负数的符号。再一次,我们看到我们正在执行2的幂的除法。

票数 1.8K
EN

Stack Overflow用户

发布于 2008-09-26 22:22:04

位操作,包括位移位,是底层硬件或嵌入式编程的基础。如果您阅读设备的规范,甚至是一些二进制文件格式,您将看到字节、字和双字,它们被分解为非字节对齐的位域,其中包含各种感兴趣的值。访问这些位字段以进行读/写是最常见的用法。

图形编程中的一个简单的真实示例是,16位像素表示如下:

代码语言:javascript
复制
  bit | 15| 14| 13| 12| 11| 10| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1  | 0 |
      |       Blue        |         Green         |       Red          |

要获得绿色值,您可以执行以下操作:

代码语言:javascript
复制
 #define GREEN_MASK  0x7E0
 #define GREEN_OFFSET  5

 // Read green
 uint16_t green = (pixel & GREEN_MASK) >> GREEN_OFFSET;

说明

为了获得绿色的值,它从偏移量5开始,到10结束(即6位长),你需要使用一个(位)掩码,当它应用于整个16位像素时,将只产生我们感兴趣的位。

代码语言:javascript
复制
#define GREEN_MASK  0x7E0

适当的掩码为0x7E0,二进制为0000011111100000 (十进制为2016 )。

代码语言:javascript
复制
uint16_t green = (pixel & GREEN_MASK) ...;

要应用遮罩,请使用AND运算符(&)。

代码语言:javascript
复制
uint16_t green = (pixel & GREEN_MASK) >> GREEN_OFFSET;

在应用掩码之后,您将得到一个16位的数字,它实际上只是一个11位的数字,因为它的MSB是第11位。绿色实际上只有6位长,所以我们需要使用右移位(11 -6= 5)来缩小它,因此使用5作为偏移量(#define GREEN_OFFSET 5)。

同样常见的是使用位移位进行快速乘法和2次方除法:

代码语言:javascript
复制
 i <<= x;  // i *= 2^x;
 i >>= y;  // i /= 2^y;
票数 109
EN

Stack Overflow用户

发布于 2015-03-31 18:49:23

位掩码和移位

在低级图形编程中经常使用位移位。例如,以32位字编码的给定像素颜色值。

代码语言:javascript
复制
 Pixel-Color Value in Hex:    B9B9B900
 Pixel-Color Value in Binary: 10111001  10111001  10111001  00000000

为了更好地理解,相同的二进制值标注了哪些部分代表哪些颜色部分。

代码语言:javascript
复制
                                 Red     Green     Blue       Alpha
 Pixel-Color Value in Binary: 10111001  10111001  10111001  00000000

比方说,我们想要得到这个像素颜色的绿色值。我们可以很容易地通过掩码和移位来获得该值。

我们的面具:

代码语言:javascript
复制
                  Red      Green      Blue      Alpha
 color :        10111001  10111001  10111001  00000000
 green_mask  :  00000000  11111111  00000000  00000000

 masked_color = color & green_mask

 masked_color:  00000000  10111001  00000000  00000000

逻辑&运算符确保只保留掩码为1的值。我们现在要做的最后一件事,是通过将所有这些位向右移位16位(逻辑向右移位)来获得正确的整数值。

代码语言:javascript
复制
 green_value = masked_color >>> 16

Et voilà,我们有一个整数来表示像素颜色中的绿色数量:

代码语言:javascript
复制
 Pixels-Green Value in Hex:     000000B9
 Pixels-Green Value in Binary:  00000000 00000000 00000000 10111001
 Pixels-Green Value in Decimal: 185

这通常用于编码或解码图像格式,如jpgpng等。

票数 55
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/141525

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档