美文网首页
C高阶1:二进制操作

C高阶1:二进制操作

作者: jdzhangxin | 来源:发表于2019-04-14 09:07 被阅读0次

1. 位运算

  1. 按位运算

    No. 操作符 功能
    1 & 按位与
    2 | 按位或
    3 ~ 按位取反
    4 ^ 按位异或
  2. 运算规则

    p q p & q p | q p ^ q
    0 0 0 0 0
    0 1 0 1 1
    1 1 1 1 0
    1 0 0 1 1
  3. 示例

    1. 按位与
      让某一位或某些位为0

      int n = 0xFFFF;
      n = n & 0x0010;
      

      截取二进制数中的一段值。

      int n = 0xFFab;
      n = n & 0x00FF;
      
    2. 按位或
      让某一位或某些位为1

      int n = 0x0000;
      n = n | 0x0010;
      

      拼接两个二进制数。

      int a = 0xab00;
      int b = 0x0012;
      int c = a|b;
      
    3. 按位取法
      得到全部为1的数字~0

      int n = ~0;// 等同于0xFFFF
      

      使数字的部分清零x& ~7

      int n = 0xFFFF;
      n = n & ~7;
      
    4. 按位异或
      两个相等数异或结果为0

      int n = 0x1234;
      n = n^n;
      

      对同一个变量两次异或,变会原值。

      int a = 0x1234;
      int b = 0x1357;
      a = a^b;
      a = a^b;
      

逻辑运算与按位运算

  1. 逻辑运算结果只有01两种值,按位运算有多种值。
  2. 逻辑运算相当于把所有的非零值都变成1,再按位运算。
  1. 练习

2. 移位运算

No. 操作符 功能
1 << 左移
2 >> 右移
  1. 左移
    i<<j表示i中所有位向左移动j个位置,右边填入0
    所有小于int的类型,移位以int大小执行,结果为int

  2. 右移
    i>>j表示i中所有位向右移动j个位置,
    对于unsigned类型,左边填入0;对于signed类型,左边填入符号位。
    所有小于int的类型,移位以int大小执行,结果为int

  3. 位移运算与乘除运算
    位移运算与乘除运算运算有如下对应关系:

    No. 位移运算 乘除运算
    1 x<<1 x*2
    2 x>>1 x/2
    3 x<<n x*pow(2,n)
    4 x>>n x/pow(2,n)
    5 x<<=1 x*=2
    6 x>>=1 x/=2
    7 x<<=n x*=pow(2,n)
    8 x>>=n x/=pow(2,n)
  • 试一试
    x<<-2;// 未定义行为
    
  • 练习
    1. 位的设置
      i |= 1<<j;
      
    2. 位的清除
      i &= ~(1<<j);
      
    3. 位的测试
      i & 1<<j
      
  • 实践
    用位表示下面的结构体。
typedef struct{
    bool student; // true:表示学生,false:表示非学生
    bool sex; // true:表示男,false:表示女
    bool pass; // true:表示合格,false:表示不合格
};

3. 位域

3.1 位域是什么?

位域是又称作位段,是把一个字节中的二进位划分为几个不同的区域。

3.2 位域有什么用?

节省空间,有些信息不需要占用一个完整的字节。

3.3 位域怎么用?

  1. 定义位域
    定义位域与结构定义相仿。

    • 语法
      struct 位域结构名{ 
          类型 位域名:位域长度;
      };
      
      为了保证位域的可以移植性,成员类型通常为unsigned intint,C99可以使用bool
    • 示例
      struct Byte{
        unsigned int b1:1;
        unsigned int b2:1;
        unsigned int b3:1;
        unsigned int b4:1;
        unsigned int b5:1;
        unsigned int b6:1;
        unsigned int b7:1;
        unsigned int b8:1;
       };
      
  2. 位域变量
    定义和使用位域变量与结构体相同。每个域有一个域名,允许在程序中按域名进行操作。

    void printByte(struct Byte a){
      printf("%d",a.b1);
      printf("%d",a.b2);
      printf("%d",a.b3);
      printf("%d",a.b4);
      printf("%d",a.b5);
      printf("%d",a.b6);
      printf("%d",a.b7);
      printf("%d\n",a.b8);
    }
    int main () {
    struct Byte a;
    printByte(a);
    struct Byte b = {1,0,1,0,1,0,1,0,};
    printByte(b);
    return 0;
    }
    

    试一试

    struct Byte c = {1,2,3,4,5,6,7,8,};
    printByte(c);
    
    void scanfByte(struct Byte* a){
    scanf("%d",&a.b1);
    scanf("%d",&a.b2);
    scanf("%d",&a.b3);
    scanf("%d",&a.b4);
    scanf("%d",&a.b5);
    scanf("%d",&a.b6);
    scanf("%d",&a.b7);
    scanf("%d",&a.b8);
    }
    
  3. 位域大小

    printf("sizeof(Byte) = %ld\n",sizeof(Byte));
    
    struct Byte{
        unsigned char b1:1;
        unsigned char b2:1;
        unsigned char b3:1;
        unsigned char b4:1;
        unsigned char b5:1;
        unsigned char b6:1;
        unsigned char b7:1;
        unsigned char b8:1;
    };
    

    位域的存储由编译器实现决定。编译器规定存储单元大小(8位、16位、32位)。 编译器会把位域逐个放入存储单元,位域之间没有间隙,直到存储单元放不下下一个位域,然后从下个存储单元继续存放。也有编译器跨存储单元存放。存放顺序也是编译器决定。
    整个结构体的总大小为最宽基本类型成员大小的整数倍。

相关文章

网友评论

      本文标题:C高阶1:二进制操作

      本文链接:https://www.haomeiwen.com/subject/rlldeqtx.html