C语言位操作

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言位操作相关的知识,希望对你有一定的参考价值。


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

十进制转二进制

短除法&位权法

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

C语言位操作_c++


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

例如:

二进制101010,高位在左,低位在右

C语言位操作_开发语言_02

十进制转二进制函数

#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​​​ 左右有两个运算对象,分别为​​12345​​与​​67890​​。左边的运算对象​​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表示。

前四位为例

C语言位操作_运算符_03


C语言位操作_c语言_04


C语言位操作_开发语言_05


C语言位操作_c++_06

位逻辑或|

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

C语言位操作_运算符_07

位逻辑异或^

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

C语言位操作_开发语言_08

位逻辑非~

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

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

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

C语言位操作_十进制_09

左移右移

左移运算符​​<<​

左移运算符将数据对象内部的二进制全部向左移动指定位,空出来的位置用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

C语言位操作_十进制_10

右移运算符

右移运算符将数据对象内部的二进制全部向右移动指定位,对于无符号类型,空出来的位置用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语言位操作_开发语言_11


20160402_C语言位操作符的使用

  

  C语言的设计具备了汇编语言的运算能力,它支持全部的位操作符。

  位操作符是对字节或字中的位进行测试、置位或移位处理,在对微处理器的编程中,特别适合对寄存器、I/O端口进行操作。

 

  6种位操作符:

  (1) & :按位“与”——仅当两个操作数为1时,结果为1,否则为0。如:1000 1000  & 1000 0001  = 1000 0000;

  (2) | :按位“或”——仅当两个操作数为0时,结果为0,否则为1。如:1000 1000 | 1000 0001 = 1000 1001;

  (3) ^:按位“异或”——仅当两个操作数不同时,相应的输出结果才为1,否则为0。

               如:1000 1000 ^ 1000 0001 = 0000 1001 ;

  (4) ~ :“取反”——把1置为0,0置为1。如:~1000 1000 = 0111 0111;

  (5) <<: “左移”——将变量的各位按要求向左移动若干位。如:0000 1000 <<3 = 0100 0000;

  (6) >>: “右移”——将变量的各位按要求向右移动若干位。如:0000 1000>>3=0000 0001;

 

  位运算符的应用:

  (1)直接交换两个变量的值

  例如,若有变量a = 3,b = 4,想要交换它们的值,可以做如下一组操作:

 

    a ^ = b  (a等于a异或b)

    b ^ = a  (b等于b异或a)

    a ^ = b  (a等于a异或b)

 

  首先,a ^ = b:

       a    0000 0011

  ^   b    0000 0100

   a =     0000 0111

 

  其次,b ^ = a:

       b    0000 0100

  ^   a    0000 0111

   b =     0000 0011

 

  最后,a ^ = b:

       a    0000 0111

  ^   b    0000 0011

   a =     0000 0100

 

  这样,a、b两个变量中的值就进行了对调。

 

  (2)快速乘除运算

  移位操作可用于整数的快速乘除运算,左移一位等效于乘2,而右移一位等效于除以2。

  如:x = 7, 二进制表达为:0000 0111,

  x < < 1               0000 1110,相当于: x =2*7=14,

  x < < 3               0111 0000,相当于: x=14*2*2*2=112

  x < < 2               1100 0000,             x= 192

  在作第三次左移时,其中一位为1的位移到外面去了,而左边只能以0补齐,因而便不等于112*2*2=448,而是等于192了。当x按刚才的步骤反向移动回去时,就不能返回到原来的值了,因为左边丢掉的一个1,再也不能找回来了:

  x > > 2              0011 0000,          x=48

  x > > 3              0000 0110            x=48/8=6

  x > > 1              0000 0011            x=6/2=3

 

  (3)将寄存器指定位置为1

  PORTA |= (1<<n)  将porta的第n为置为1,其他为不变。比如说,你如果想将第4位置1,就使用:

  PORTA | = (1<< 4) 就行了。当然,也可以使用:

  PORTA | = (1<< 7) | (1<< 4 ) | (1<< 0) 这样的指令一次将设第8、5和1位置1,但又不影响到其它位的状态。

 

  (4)将寄存器指定位置为0

  PORTA &= ~(1<<n )

  这条指令将寄存器的任意位清0,而又不影响其它位的现有状态。比如说,你如果想将第4位清0,就使用:

  PORTA & = ~ (1<< 4) 就行了。

 

 

下面是POJ 3748题,应用了位操作符:

/*
位操作

Description

假设你工作在一个32位的机器上,你需要将某一个外设寄存器的第X位设置成0(最低位为第0位,最高位为第31位),
将第Y位开始的连续三位设置成110(从高位到低位的顺序),而其他位保持不变。对给定的寄存器值R,及X,Y,
编程计算更改后的寄存器值R。
Input

仅一行,包括R,X,Y,以逗号","分隔,R为16进制表示的32位整数,X,Y在0-31之间且Y>=3,(Y-X)的绝对值>=3,保证两次置位不会重合
Output

更改后的寄存器值R(16进制输出)
Sample Input

12345678,0,3
Sample Output

1234567c
Source

 */

#include <stdio.h>

int main()
{
 int R, X, Y;

 scanf("%x,%d,%d",&R,&X,&Y);

 R &= ~(1<<X);       // 将R的第X位设置为0
 R |= (1<<Y);        // 将R的第Y位设置为1
 Y--;
 R |= (1<<Y);        // 将R的第Y-1位设置为1
 Y--;
 R &= ~(1<<Y);       // 将R的第Y-2位设置为0

 printf("%x/n",R);

 return 0;
}

以上是关于C语言位操作的主要内容,如果未能解决你的问题,请参考以下文章

用C语言接收用户输入的一个四位数,用while循环计算个位,十位,百位,千位之和,

C语言位操作

C语言怎样提取一个数的十位个位百位千位?

C语言怎样提取一个数的十位个位百位千位?

用c语言设计一个计算两个整数的和、差、积、商、和余数的程序

c语言 操作符系统解读