C++移位运算符

关于逻辑移位、算术移位可参见迅雷深大笔试题部分。的一道题。以前看到C++标准上说,移位运算符(<<、>>)出界时的行为并不确定:Thebehaviorisundefi

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

关于逻辑移位、算术移位可参见迅雷深大笔试题部分。的一道题。

以前看到C++标准上说,移位运算符(<<、>>)出界时的行为并不确定:

The behavior is undefined if the right operand is negative, orgreater than or equal to the length in bits of the promoted left operand.

我当时也没有深究过这个问题。前几天有个网友来信问起这件事,我才发现,这和IntelCPU的移位运算有关。下面是那位网友的来信以及我的回复:

 

您好!运算符<<作为位操作中的高效的操作,但我遇到一个问题:下面在VC环境下发现一个很不明白的地方,下面标注。

#include <stdio.h>

void main()

{

   unsigned int i,j;

   i=35;

 

   //为什么下面两个左移操作结果不一样?

   j=1<<i;  // j为8

   j=1<<35; // j为0

}

不知是哪里没有理解对。

 

原因是这样的:i=35;j=1<<i;这两句在VC没有做优化的情况下,将被编译成下面的机器指令:

mov dword ptr [i],23h

mov eax,1

mov ecx,dword ptr [i]

shl eax,cl

mov dword ptr [j],eax

在shl一句中,eax=1,cl=35。而IntelCPU执行shl指令时,会先将cl与31进行and操作,以限制左移的次数小于等于31。因为35 & 31 =3,所以这样的指令相当于将1左移3位,结果是8。

而j=1<<35;一句是常数运算,VC即使不做优化,编译器也会直接计算1<<35的结果。VC编译器发现35大于31时,就会直接将结果设置为0。这行代码编译产生的机器指令是:

mov dword ptr [j],0

对上面这两种情况,如果把VC编译器的优化开关打开(比如编译成Release版本),编译器都会直接将结果设置为0。

所以,在C/C++语言中,移位操作不要超过界限,否则,结果是不可预期的。

http://hovertree.com/menu/cpp/

下面是Intel文档中关于shl指令限制移位次数的说明:

The destination operand can be a register or a memory location.The count operand can be an immediate value or register CL. The count is maskedto 5 bits, which limits the count range to 0 to 31. A special opcode encodingis provided for a count of 1.

 

 

1.掩码

就是一串2进制 对目标字段进行位与运算,屏蔽当前的输入位。

将源码与掩码经过逻辑运算得出新的操作数。其中要用到逻辑运算如OR运算。AND运算。用于如将ASCLL码中大写字母改作小写字母。

2.与 或 异或 转换成补码运算

3.  用法:掩码 (&)

4. 用法:打开位 (|)

5.用法:关闭位 (&~)

6. 用法:转置位 (^)

7. 将Value的第bit_number位置1       Value |= 1 << bit_number;

8. 将Value的第bit_number位置0       Value &= ~( 1 << bit_number );

9.value & 1 << bit_number 如果该位置已被置为1,则表达式的结果为非零值

 

C/C ++提供位逻辑运算符和移位运算符。二者只能用于整形和字符型。位运算符是对每位进行操作而不影响左右两位,这有别于常规运算符(&&|| !)是将整个数进行操作的。

一.    位逻辑运算符

1.    ~ 按位取反

将1变为0,将0变为1

EG:

~(10011010)

(01100101)

注:

VC++编译器,计算~10,得出的结果是-11。为什么不是5呢

10的二进制表示为1010,按位取反应该为0101,也就是十进制的5,为什么会得出-11?

VC是32位编译器,所以

10 = 00000000 00000000 00000000   00001010

~10 = 11111111 11111111   11111111   11110101 =   -11

可以通过掩码(位与) 与15位与

   15 = 00000000 00000000 00000000   00001111

~10 = 00000000 00000000 00000000   00000101   =   -11

2.    & 按位取与

只有两个操作数都是1结果才是1,否则为0

10 = 00000000 00000000 00000000   00001010

12 = 00000000 00000000 00000000   00001100

&

8 = 00000000 00000000 00000000   00001000

3.    | 按位取或

两个操作数任意一位为1结果就是1

10 = 00000000 00000000 00000000   00001010

12 = 00000000 00000000 00000000   00001100

|

14 = 00000000 00000000 00000000   00001110

      

4.    ^ 按位异或

两个操作数不同为1,相同为0

10 = 00000000 00000000 00000000   00001010

12 = 00000000 00000000 00000000   00001100

^

14 = 00000000 00000000 00000000   00000110

       

5.    用法:掩码

掩码是通过&(位与)将某些位设置为开(1),将某些位设置为关(0)。将掩码0看做不透明,将1看着透明。

EG:

如只显示第二、三位

107 = 0110 1011

6            = 0000 0110

&

2   = 0000 0010

       

6.    用法:打开位

打开位是通过 |(位或)打开一个值的特定位,同时保持其他位的不变。这是因为和0位或都为0,和1位或都为1。

EG:

如只打开第二、三位

107 = 0110 1011

6   = 0000 0110

|

111 = 0110 1111

7.    用法:关闭位

关闭某些位

EG:

如关闭第二、三位

107 = 0110 1011

6    = 0000 0110

& ~

105 = 0110 1001

8.    用法:转置位

如果一位为1则转置为0,如果一位为1则转置为0

EG:

如转置第二、三位

107 = 0110 1011

6    = 0000 0110

^

105 = 0110 1101

       

二.    移位运算符

  1. << 左移

左移运算符是把操作数的值的每一位向左移动,移动的位数有右边的操作数决定,右侧空出的位数用0填充

EG:

如转置第二、三位

107 = 0110 1011 <<2

<<

172 = 1010 1100

      

       在计算机中由于是32位的

107 = 0000 0000   0000 0000   0000 0000   0110 1011 <<2

<<

428 = 0000 0000   0000 0000   0000 0001   1010 1100

  1. >> 右移

右移运算符是把操作数的值的每一位向右移动,移动的位数有右边的操作数决定,左边丢弃的位数用0填充

EG:

如转置第二、三位

107 = 0110 1011 >>2

>>

26 = 0001 1010

 

 

 

一、传统的C方式位操作:

1.基本操作:

   使用一个unsigned int变量来作为位容器。

2.操作符:

|   按位或操作符:result=exp1|exp2;当exp1和exp2中对应位中至少有一个为1时,result中对应位为1,否则为0。

&  按位与操作符::result=exp1&exp2;当exp1和exp2中对应位全为1时,result中对应位为1,否则为0。

^  按位异或或操作符:result=exp1^exp2;当exp1和exp2中对应位不相同时,result中对应位为1,否则为0。

~  反转操作符:将位容器中的所有位都反转,1变为0,0变为1。

<< 按位左移操作符:exp<<n,将容器中所有的位向左移n位,空出的位用0填充。

>> 按位右移操作符:exp>>n,将容器中所有的位向右移n位,空出的位用0填充。

|=,&=,^= 分别对应|&^三种操作符的复合操作符。

3.常用操作

   这里我们假设有一个result的unsigned int变量用来储存32个学生的成绩(通过和不通过分别用0和1),这样result就有33位(result从右至左,从0开始计算位数,在这个例子中0位被浪费)。

(a) 将第27位设置为及格(设作1)其他位不变:

   result|=(1<<27) //任意的位值与1作按位或操作其值为1,而与0作按位与操作其值不变

(b) 将第27位设置成不及格(设为0)。

   result&=~(1<<27) //任意的位值与0作按位与操作其值为0,而与1作按位与操作其值不变

(c) 反转第27位的值。

   result^=(1<<27) //任意的位值与1作按位异或操作其值为1,而与0作按位异与操作其值不变

 

二、C++中的bitset容器

1.头文件:

  #include <bitset>

2.声明一个容器:

 (a)声明一个指定位数的空容器(所有位设为0): bitset<int> bits;

 (b)声明一个指定位数并将指定的几个位初始化为相应值的容器: bitset<n> bits(int);

     bitdet<int> bits(string&)

总结:bitset模板类中类型参数传递容器的位数,而构造函数参数通过一个int或一个string&值来从右至左初始化容器中的相应值。

3.bitset的基本用法:

操作

功能

用法

test(pos)

pos位是否为1?

a.test(4)

any()

任意位是否为1?

a.any()

none()

是否没有位为1?

a.none()

count()

值是1的位的小数

count()

size()

位元素的个数

size()

[pos]

访问pos位

a[4]

flip()

翻转所有位

a.flip()

flip(pos)

翻转pos位

a.flip(4)

set()

将所有位置1

a.set()

set(pos)

将pos位置1

a.set(4)

reset()

将所有位置0

a.reset()

reset(pos)

将pos位置0

a.reset(4)

4.bitset与传统C位操作及字符串的转换

   可以通过to_string()成员将容器转输出为一个string字符串,另外还可以用to_long()成员将容器输出到传统的用于C风格的位容器中。如:

  unsigned long bits = bits.to_long();

  sting str(bits.to_string());

 

推荐:http://www.cnblogs.com/roucheng/p/cppjy.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/120400.html原文链接:https://javaforall.net

(0)
上一篇 2021年12月26日 下午1:00
下一篇 2021年12月26日 下午1:00


相关推荐

  • bootstrap 页面垂直居中_bootstrap div垂直居中+水平居中保持响应式

    bootstrap 页面垂直居中_bootstrap div垂直居中+水平居中保持响应式引入 bootstrap4cs 文件 只在 bootstrap4 有效 bs3 效果不太行 垂直居中 为需要垂直居中的 div 新建如下样式 col center block position absolute top 50 webkit transform translateY 50 moz transform translateY 50 ms transform tran

    2026年1月16日
    2
  • mysql批量增加数据_数据库最大连接数设置为多少合适

    mysql批量增加数据_数据库最大连接数设置为多少合适文章目录一、前言二、批量插入前准备1、插入到数据表的字段2、计算一行字段占用的空间3、在数据里做插入操作的时候,整体时间的分配三、批量插入数据测试1、SQL语句的大小限制2、查看服务器上的参数:3、计算一次能插入的最大行记录4、测试插入数据比对(1)插入11W条数据,按照每次10,600,1000,20000,80000来测试:(2)加大数据量到24w(3)加大测试量到42W5、如果插入的值就是sql语句限制的最大值,那么性能真的好吗?四、其他影响插入性能的因…

    2026年4月16日
    10
  • 3步教你精准定调产品风格!电商设计小白也能快速出爆款

    3步教你精准定调产品风格!电商设计小白也能快速出爆款

    2026年3月15日
    2
  • Address Sanitizer使用指南

    Address Sanitizer使用指南提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档文章目录前言一 pandas 是什么 二 使用步骤 1 引入库 2 读入数据总结前言 AddressSanit 使用提示 以下是本篇文章正文内容 下面案例可供参考一 pandas 是什么 示例 pandas 是基于 NumPy 的一种工具 该工具是为了解决数据分析任务而创建的 二 使用步骤 1 引入库代码如下 示例 importnumpya

    2025年8月3日
    5
  • sql语句快速清空表

    sql语句快速清空表对于sql清空表有三种清空方式1.delete——是逐行删除速度极慢,不适合大量数据删除2.truncate—-删除所有数据,保留表结构,不能撤消还原3.drop——–删除表,数据和表结构一起删除,快速但是在实践过程中我发现,1,2这两种方法在处理大量数据的时候都比较慢,往往要等待许久才能清空完成。所以我考虑还有没有其他的方法达到清空表的作用呢。后来我从导出表结构中…

    2022年5月5日
    129
  • .NET(c#) 移动APP开发平台 – Smobiler(2) – 平台介绍

    .NET(c#) 移动APP开发平台 – Smobiler(2) – 平台介绍  看到大家很多人在后台问我一些问题,所以准备写一个系列了,下面给个目录目录:   .NET(c#)移动APP开发平台-Smobiler(1) 环境的搭建及上手第一个应用类似开发WinForm的方式,使用C#开发Android和IOS的移动应用?听起来感觉不可思议,但是实际上确实很强大,那么Smobiler平台到底是如何实现的呢,这里给大家介绍一下。客户端  Smobi…

    2022年5月29日
    73

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号