zoukankan      html  css  js  c++  java
  • C Primer Plus之位操作

       二进制补码表示法

       几乎所有的计算机都使用二进制补码表示法来存储位于n位存储单元中的有符号整数。

       在二进制补码表示法中,最左位决定符号。如果它是0,该整数为正(即非负);如果是1,该整数为负。

       两种运算:

    1. 反码(或取一个整数的反码):简单反转各个位,即把0位变为1位,把1位变为0位。
    2. 补码(或取一个整数的补码):方法一,首先,从右边复制位,直到有1被复制;接着,反转其余的位。方法二,先对它进行1次反码运算再加上1得到结果。

       以二进制补码格式存储整数,计算机遵循以下步骤:

    • 将整数变成n位的二进制数
    • 如果整数是正数或零,以其原样存储;如果是负数,计算机取其补码存储。

       以二进制补码格式还原整数,计算机遵循以下步骤:

    • 如果最左位是1,计算机取其补码。如果最左位是0,计算机不进行操作。
    • 计算机将该整数转换为十进制

       二进制补码表示法只有一个0。

       

       位逻辑运算符

       1° 二进制反码或按位取反:~

       2° 位与(AND):&

           对于每个位,只有两个操作数的对应位都为1时结果才为1(用真/假来描述,只有两个位操作数都为真结果才为真)。C也有一个组合的位与-赋值运算符:&=,例:

    val &= 0377;
    val = val & 0377;

       3° 位或(OR):|

           对于每个位,如果其中任意操作数中对应的位为1,那么结果位为就为1(用真/假来描述,如果任意一个位操作数为真,或两个都为真,那么结果为真)。C也有一个组合的位或-赋值运算符:|=

       4° 位异或:ˆ

           对于每个位,如果操作数中的对应位有一个为1(但是不都为1),那么结果为1(用真/假来描述,如果两个位操作数中有一个为真,但是不都为真,那么结果为真)。C也有一个组合的位异或-赋值运算符:ˆ=

       4个位运算符用于整数数据,包括char。将这些运算符称为位运算符的原因是它们对每位进行操作,而不影响左右两侧的位。请不要将这些运算符与常规的逻辑运算符相混淆(&&、||、!),常规的逻辑运算符对整个值进行操作

       移位运算符

       1° 左移:<<

       左移运算符<<将其左侧操作数的值的每位向左移动,移动的位数由其右侧操作数指定。空出的位用0填充,并且丢弃移出左侧操作数末端的位。可以使用左移-赋值运算符(<<=)来实际改变一个变量的值。该运算符将变量中的位向左移动右侧值大小的位置。

       2° 右移:>>

       右移运算符>>将其左侧操作数的值的每位向右移动,移动的位数由其右侧操作数指定。丢弃移出左侧操作数右端的位。对于unsigned类型,使用0填充左端空出的位。对于有符号类型,结果依赖于机器。空出的位可能用0填充,或者使用符号(最左端的)位的副本填充。右移-赋值运算符(>>=)将左侧变量的位向右移动指定数量的位置。

       移位运算符能够提供快捷、高效的(依赖于硬件)对于2的幂的乘法和除法:

    number << n number乘以2的n次幂
    number >> n 如果number非负,则用number除以2的n次幂

       

       位字段

       位字段是一个signed int或unsigned int中一组相邻的位(C99还允许_Bool类型位字段)。位字段由一个结构声明建立,该结构声明为每个字段提供标签,并决定字段的宽度。例如,以下建立了4个1位字段:

    struct {
         unsigned int autfd: 1;
         unsigned int bldfc: 1;
         unsigned int undln: 1;
         unsigned int itals: 1;
    } prnt;

       ↓ 使用普通的结构成员运算符将值赋给单独的字段

    prnt.itals = 0;
    prnt.undln = 1;

       prnt变量存储在一个int大小的存储单元中,但仅有其中的4位被调用。

       字段不限于1位大小。

    struct {
         unsigned int code1: 2;
         unsigned int code2: 2;
         unsigned int code3: 8;
    } prcode;

       ↓ 这段代码创建两个2位字段和一个8位字段(只须确保值没有超出字段的容量)

    prcode.code1 = 0;
    prcode.code1 = 3;
    prcode.code1 = 102;

       问题:如果您所声明的总位数超过一个unsigned int大小,那么将会发生什么?

       答:那将会使用下一个unsigned int存储位置。不允许一个字段跨越两个unsigned int之间的边界。编译器自动地移位一个这样的字段定义,使字段按unsigned int边界对齐。

    发生这种情况时,会在第一个unsigned int中留下一个未命名的

       可以使用未命名的字段宽度“填充”未命名的洞。使用一个宽度为0的未命名的字段迫使下一个字段与下一个整数对齐

    struct {
          unsigned int field1: 1;
          unsigned int       : 2;
          unsigned int field2: 1;
          unsigned int       : 0;
          unsigned int field3: 1;
    } stuff;    // stuff.field1和stuff.field2之间有一个2位的间隙,stuff.field3存储在下一个int中

       位字段往往难以移植,所以,把它们用于不可移植的用途,例如按照某个特定硬件设备所使用的确切格式来存放数据。

  • 相关阅读:
    Eclipse 快捷键
    计算机网络之读Internet网发展史 读后感
    计算机网络之读Internet网发展史 读后感
    动态加载布局的技巧
    二、JSP的3个编译指令,7个动作指令,9个内置对象
    【杭电】[2050]折线分割平面
    【杭电】[2050]折线分割平面
    【杭电】[2068]RPG的错排
    【杭电】[2068]RPG的错排
    【杭电】[4500]小Q系列故事——屌丝的逆袭
  • 原文地址:https://www.cnblogs.com/yerenyuan/p/5103708.html
Copyright © 2011-2022 走看看