C位操作

简介: C位操作

深入到字节的内部,讨论如何直接操作字节内部的二进制位

十进制转二进制

短除法&位权法

先读高位、后读低位从下往上逆序读右侧的余数101010。这就是十进制数42所对应的二进制。

将二进制转换为十进制,可以把二进制中的各位乘以其所在位的位权,再将所有乘法的积累加起来,即可得到转换后的十进制结果。
例如:
二进制101010,高位在左,低位在右

十进制转二进制函数

#include<stdio.h>
void printBinary(unsigned char dec) {
    // 若dec为0,输出0并返回
    if (dec == 0)
    {
        printf("0\n"); return;
    }
    // 若dec非0,短除计算余数,逆序输出
    char bits[8];
    int count = 0;
    int quotient;
    int remainder;
    while (dec > 0)
    {
        remainder = dec % 2;
        quotient = dec / 2;
        dec = quotient;
        bits[count] = remainder;
        count++;
    }
    for (int i = count - 1; i >= 0; i--)
        printf("%d", bits[i]);
    putchar('\n');
}
int main() {
    printBinary(42);//以42为例
}
正确输出
101010

对于unsigned char类型的变量dec来说,它拥有8个二进制位。而十进制数42,只占6个二进制位,还有两个二进制位为0。若需要把8个二进制位全部输出,可以将bits数组初始化为0。计算完余数后,从数组的最后一个元素开始,逆序输出直到数组第一个元素。此时,无需对dec为0做特殊处理了。由于数组bits初始化为0,dec为0时,不进入while循环,直接输出8个0。

#include<stdio.h>
void printBinary(unsigned char dec) {
    char bits[8] = {0};
    int count = 0;
    int quotient;
    int remainder;
    while (dec > 0)
    {
        remainder = dec % 2;
        quotient = dec / 2;
        dec = quotient;
        bits[count] = remainder;
        count++;
    }
    for (int i = 8 - 1; i >= 0; i--)
        printf("%d", bits[i]);
    putchar('\n');
}
int main() {
    printBinary(42);
}
补齐0
00101010

逻辑运算符

逻辑运算符会把运算对象的数值,看做真或假进行逻辑运算。若运算对象的数值为非0值,则看做真。若数值为0值,则看做假。
下面分别复习一下这3种逻辑运算符。

逻辑与&&

逻辑与&&运算符会对左右两边,两个运算对象进行运算。

  1. 若两个运算对象同时为真时,运算结果为真,用数值1表示。
  2. 否则,运算结果为假,用数值0表示。

12345 && 67890
左右有两个运算对象,分别为1234567890。左边的运算对象12345为非0值,看做真。右边运算对象67890为非0值,看做真。两个运算对象同时为真,运算结果为真,即1。
若将其中一边变为0,表达式如下:
12345 && 0
左边的运算对象12345为非0值,看做真。右边运算对象0为0值,看做假。两个运算对象不同时为真,运算结果为假,即0。

逻辑或||

逻辑或||运算符会对左右两边,两个运算对象进行运算。

  1. 若两个运算对象同时为假时,运算结果为假,用数值0表示。
  2. 否则,运算结果为真,用数值1表示。

12345 || 0
左边的运算对象12345为非0值,看做真。右边运算对象0为0值,看做假。两个运算对象不同时为假,运算结果为真,即1。
0 && 0
左边的运算对象0为0值,看做假。右边运算对象0为0值,看做假。两个运算对象同时为假,运算结果为假,即0。

逻辑非!

逻辑与!运算符会对右边一个运算对象进行运算:

  1. 若运算对象为真,运算结果为假。
  2. 若运算对象为假,运算结果为真。

!12345
右边运算对象12345为非0值,看做真。运算结果为假,即0。
!0
右边运算对象0为0值,看做假。运算结果为真,即1。

位运算符

在上面的逻辑运算中,会把运算对象的数值根据非0值或0值,看做真或假,再进行逻辑运算。
还有另外一类运算符,它将深入运算对象的内部,把运算对象内部的二进制位,根据非0值或0值,看做真或假,再进行逻辑运算。

位逻辑运算符:

  1. 位逻辑与&
  2. 位逻辑或|
  3. 位逻辑异或^
  4. 位逻辑非~

将十进制170作为函数printBinary的参数,它将打印出十进制170的二进制10101010
将十进制102作为函数printBinary的参数,它将打印出十进制102
的二进制01100110
接下来,我们让这两个数值分别做各种位逻辑运算,看看它们都有什么现象。

位逻辑与&

printf("%hhu\n", 170 & 102);
printBinary(170 & 102);

位逻辑与&它将深入字节内部,对二进制位进行逻辑与运算。

  1. 若两个位同时为真,运算结果为真,用数值1表示。
  2. 否则,运算结果为假,用数值0表示。
前四位为例




位逻辑或|

  1. 若两个位同时为假时,运算结果为假,用数值0表示。
  2. 否则,运算结果为真,用数值1表示。

位逻辑异或^

  1. 若两个位不同时,运算结果为真,用数值1表示。
  2. 否则,运算结果为假,用数值0表示。

位逻辑非~

位逻辑非~它将深入字节内部,对二进制位进行逻辑非运算。

  1. 若二进制位为真时,运算结果为假,用数值0表示。
  2. 二进制位为假时,运算结果为真,用数值1表示。

换句话说,位逻辑非运算会翻转运算对象的所有二进制位。二进制位1变为0,0变为1。

左移右移

左移运算符<<

左移运算符将数据对象内部的二进制全部向左移动指定位,空出来的位置用0填充。

#include<stdio.h>
void printBinary(unsigned char dec) {
    char bits[8] = {0};
    int count = 0;
    int quotient;
    int remainder;
    while (dec > 0)
    {
        remainder = dec % 2;
        quotient = dec / 2;
        dec = quotient;
        bits[count] = remainder;
        count++;
    }
    for (int i = 8 - 1; i >= 0; i--)
        printf("%d", bits[i]);
    putchar('\n');
}
int main() {
    printBinary(231);
    printBinary(231 << 1);
    printBinary(231 << 2);
    printBinary(231 << 3);
}
输出结果
11100111
11001110
10011100
00111000

右移运算符

右移运算符将数据对象内部的二进制全部向右移动指定位,对于无符号类型,空出来的位置用0填充。
对于有符号类型,空出来的位置用0或1填充取决于编译器。

#include<stdio.h>
void printBinary(unsigned char dec) {
    char bits[8] = {0};
    int count = 0;
    int quotient;
    int remainder;
    while (dec > 0)
    {
        remainder = dec % 2;
        quotient = dec / 2;
        dec = quotient;
        bits[count] = remainder;
        count++;
    }
    for (int i = 8 - 1; i >= 0; i--)
        printf("%d", bits[i]);
    putchar('\n');
}
int main() {
    printBinary(231);
    printBinary(231 >> 1);
    printBinary(231 >> 2);
    printBinary(231 >> 3);
}
输出结果
11100111
01110011
00111001
00011100

目录
相关文章
|
存储 C#
C# 逻辑位运符及运算原理 按位操作二进制
C# 逻辑位运符及运算原理 按位操作二进制
|
7月前
|
C语言
C语言自增减、逻辑运算、位运算、位移运算及三目运算操作
C语言自增减、逻辑运算、位运算、位移运算及三目运算操作
52 0
位操作(异或骚操作)
位操作(异或骚操作)
46 0
3 位操作指令【微机原理】
3 位操作指令【微机原理】
42 0
深入理解位操作( 一)
深入理解位操作( 一)
85 0
|
人工智能 BI
第三次笔记:算术逻辑单元 电路基本原理 加法器的设计 一位全加器 串行进位加法器 并行进位加法器 补码加减运算器 无符号整数加减法 标志位的生成
第三次笔记:算术逻辑单元 电路基本原理 加法器的设计 一位全加器 串行进位加法器 并行进位加法器 补码加减运算器 无符号整数加减法 标志位的生成
455 0
第三次笔记:算术逻辑单元 电路基本原理 加法器的设计 一位全加器 串行进位加法器 并行进位加法器 补码加减运算器 无符号整数加减法 标志位的生成
|
C语言 编译器
C语言里的左移和右移运算
在用gcc编译这段程序的时候编译器会给出一个warning,说左移位数>=类型长度.那么实际上i,j移动的就是1位,也就是33%32后的余数.在gcc下是这个规则,别的编译器是不是都一样现在还不清楚.
2105 0
|
存储 Web App开发 算法
二进制究竟有什么用?齐姐带你看看那些好玩儿的「位操作」
本篇终于讲到了齐姐文章里常常出现的分割线! 计算机说到底就是 0 和 1,所有的数在内存中都是以二进制的形式储存的。 而位操作,或者说位运算,就是直接对内存中的二进制位进行操作。 位运算可以说是我们的基本功,今天这篇文章就从以下角度和大家一起玩转位运算。
167 0
二进制究竟有什么用?齐姐带你看看那些好玩儿的「位操作」