位运算

2019春夏 程序设计专题 复盘

Posted by kamzero on 2019-08-13

位运算

数据的存储

整数数据的存储

  • 符号位
    • 最高位,最左边一位
  • 正数
    • 原码、反码、补码相同
    • 符号位为0,其余各位表示数值
    • 两个字节(2*8位,其中一位符号位)的存储单元,最大能表示正数2^15-1
  • 负数
    • 原码、补码、反码不同
    • 负数的原码
      • 符号位为1
      • 其余各位表示数值的绝对值
    • 反码
      • 符号位是1
      • 其余各位对原码取反
    • 补码
      • 反码加1
    • 两个字节(2*8位,其中一位符号位)的存储单元,最小能表示负数-2^15
  • 数值一律用补码来表示和存储
    • 使用补码,可以将符号位和数值域统一处理
    • 加法和减法也可以统一处理

实型数据的存储

不考

符号位 阶码 尾数

基本数据类型

整型

名称 类型名 字节数 数据长度 取值范围
字符型 char 1 8w
短整型 short 2 16位
整型 int 4 32位
长整型 long 4 32位
long long 64位
无符号型 区间长度一样,最大数变大从0,开始
单精度 float 4 32位 大概10^38
双精度 double 8 64位 ±10^-308~10^308

整型常量

想要输出16进制数,只需要保证相应格式%x即可,后面的数值用任意一种形式表示即可

十进制 首位不能是0 %d %u
八进制 首位必须是0 %o
十六进制 首位是0x %x

==跳过了123-130页==

输入输出

%md

  • 输出宽度为m,包括符号位
  • 数据实际宽度(含符号位)小于m,左端补空格
  • 大于m,按实际位输出
  • 右对齐
  • %0md 左侧不足位用0填充

%-md

  • 左对齐

double型输入时必须用%lf或%le

表达式

算术运算符

单目-一个操作数

双目-两个

自增和自减运算符

自增和自减运算符的对象只能是变量,不能是常量或表达式

!结合性

!按照运算符的优先级从高到低计算

!对于一个操作数,两侧哪个运算符优先级高就先与哪个结合

!优先级相同时,按结合性(结合方向)

!结合方向“从左到右”,操作数左面的运算符结合

!优先级

运算符种类 运算符 结合方向 优先级
逻辑运算符 右结合
算术运算符 ++ – + -(正负号)
* / %
+ -(加减)
关系运算符 < >
== !=
逻辑运算符 &&
||
条件表达式 ?: 右结合
赋值运算符 右结合
逗号表达式 左结合
  • a+++b是 (a++)+b

赋值表达式

  • 赋值表达式的值是运算符左侧变量的值
  • 自动类型转换
    • 赋值类型
      • 右侧类型自动转换为左侧类型
      • 运算精度可能会降低
    • 非赋值类型
      • 保证运算精度不降低
      • 水平方向&竖直方向

x * =y-3 ===== x=x * (y-3)

关系表达式

关系运算符连接,结果是一个逻辑量

3<=x<=5 ===== (3<=x)<=5

逻辑表达式

逻辑运算符连接,结果也是一个逻辑量

优先级: 非 与 或

a||3+10&&2 等价于 a || ( ( 3 + 10 ) && 2 )

! ( x == 2 ) 逻辑表达式

! x == 2 等价于 ( ! x ) == 2 关系表达式,值恒为0

!注意与和或的 短路现象!

条件表达式

运算过程与if-else类似,条件运算符是右结合,多个同级运算符时先计算右边的

如果后面两个表达式类型不同,要根据类型自动转换规则确定条件表达式的类型

n>0?2.9:1; n为负数是结果是1.0

a>b?a:c>d?c:d (a>b)?a:((c>d)?c:d)

逗号表达式

从左到右依次计算表达式1-n的值,将表达式n的值和类型作为逗号表达式的类型

位运算

运算符 优先级
~
>> << 移位运算不改变原操作数的值
&
^
|
&= |= ^= >>= <<=

操作数只能是整型or字符型以及他们的变体

区分逻辑运算和位运算

关于位运算的骚操作

异或

a^a = 0

a^~a = 二进制全1

~(a^~a) = 0

a^=b^=a^=b 交换a和b的值

同一变量与另一变量和其异或值异或等于另一个数,如(a^b)^b=a

移位
  • 循环移位
    • 移入的等于移出的
  • 逻辑移位
    • 移出的丢失,移入的为0
  • 算术移位
    • 左移,右边补0,左边舍弃
    • 右移,左端空位用最高位符号位填补,右边舍弃
      • 也有人说只有左端第一位是符号位填补,其他空位补0

int a=-2,b=1,c=0;

c |= (a >> 1) + ~b & a + 1;

1
2
>  printf("%d", c) ; 
>

-3

~b = -2

因为数均由补码表示,负数的补码是反码加1,用于加法

反正正数x取反得到的就是 -x-1