用bis和bic实现位级操作

20世纪70年代末至80年代末,DigitalEquipment的VAX计算机是一种非常流行的机型。它没有布尔运算AND和OR指令,仅仅有bis(位设置)和bic(位清除)这两种指令。两种指令的输入都是一个数据字x和一个掩码字m。

他们生成一个结果z。z是有依据掩码m的位来改动x的位得到的。使用bis指令。能够在m为1的每一个位置上,将z相应的位置设为1。

使用bic指令。能够在m为1的每一个位置上,将z相应的位置设为0。

为了弄清bis和bic运算与C语言位级运算的关系,如果我们有两个函数bis和bic来实现位设置和位清除操作。仅仅想用这两个函数,而不使用不论什么其它C语言运算,来实现按位|和^运算,即或运算和异或运算。

示比例如以下:

/*定义两个运算函数*/

int bis(intx, int m);
intbic(int x, int m);

/*或运算的实现*/

intbool_or(int x, int y){
 int result = _______;
  return result;
}

/*异或运算的实现*/int

bool_xor(int x, int y){
  int result = ______;
  return result;
}

首先来看(OR)运算的实现。先简单分析下bis运算的功能:

由给出的规则。能够得出例如以下演示样例:

bis([1001],[0110])= [1111];
bis([01010101],[10011011])=[11011111];

能够得出。对于掩码m中为1的位,不管x为0或1。结果均为1,对于掩码m中位0的位,结果保持为x的值。即x为1时。结果为1,x为0时。结果为0。

这个与C语言中位级运算的或运算非常相似。所以或运算相应的结果即bis(x,y);

异或运算的结果有些复杂,先来看一下其它的稍简单的几个位级运算。

位取反运算(~)

假设要对x取反。需将0置为1,1置为0。bic函数当掩码为1时,可将结果该位置0,当掩码为0时,保持x值置结果该位。所以能够把x作为掩码,把全高位值0xFFFF作为bic函数的第一个參数。就可以对x取反。取反运算的函数能够表演示样例如以下:

int bool_not(int x){
int result =bic(0xFFFF,x); 
//此处讨论的为16位机
  return result;
}

与运算(AND)

由布尔代数可知:x&
y = ~(~x | ~y),所以由刚得出的取反运算函数。可得出与运算的函数:

int bool_and(int x, int y){
  int result =bic(0xFFFF,bis(bic(0xFFFF,x),bic(0xFFFF, y));
  return result;
}

以下探讨下位异或运算(XOR)

异或运算,仅仅有当两个位不同一时候。结果才为1。

用1位数位能够表示成例如以下演示样例:

0^0= 0

0^1 = 1

1^0 = 1

1^1 = 0

相同用1位数位表示最简单的bis和bic函数。能够得出以下8个公式。这对于后面的分析非常实用:

bis(0,0)= 0

bis(0,1)= 1

bis(1,0) = 1

bis(1,1)= 1

bic(0,0) = 0

bic(0,1)= 0

bic(1,0) = 1

bic(1,1)= 0

注意上面标红的几个式子,恰好能够被我们利用:

对于bis函数。当两个位不同一时候,结果为1。而bic函数却取决于掩码的数值。对于bic函数,当两个位同样时。结果为0。所以能够得出以下几个式子:

bis(bic(0,1),bic(1,0))=bis(0,1)=1
bis(bic(1,0),bic(0,1))= bis(1,0)= 1
bis(bic(0,0),bic(0,0))= bis(0,0)= 0
bis(bic(1,1),bic(1,1))= bis(0,0)= 0

这就是对于(0,1)、(1,0)、(0,0)和(1,1)四对数位的异或运算结果。所以异或运算可写成例如以下形式:

int bool_xor(int x, int y){ 
  int result =bis(bic(x,y),bic(y,x));
  return result;
}
时间: 2024-10-03 15:48:09

用bis和bic实现位级操作的相关文章

位绑定操作

总存储空间4 GByte,0x0000 0000~0xFFFF FFFF 位带区:   支持位带操作的地址区 位带别名:对别名地址的访问最终作用到位带区的访问上(注意:这中间有一个地址映射过程) 支持位绑定区域: 1.SRAM区1 MByte, 位带区字节地址  A=0x2000 0000~0x200F FFFF,位序号  n=0~7  别名区地址  AliasAddr = 0x2200 0000 + ((A-0x2000 0000)*8 + n)*4 = 0x2200 0000 + (A-0x

STM32位带操作总结---浅显易懂

正在准备做毕业设计,配置LED_Config()的时候,又看到了位带操作的宏定义,我又嘀咕了,什么是位带操作,一年前在使用位带操作的时候,就查阅过好多资料,Core-M3也看过,但是对于博主这种"低能儿"来说,你不把它说的白一点,就是感觉理解的不够透彻,于是今天又一次,查阅了各种手册,也算是基本弄懂了,鉴于博主的个人特点,所以本人的介绍也会十分浅显易懂,希望能帮到各位! 首先,抛砖引玉,来两个问题: 1)为什么STM32里面会有位带操作? 2)STM32里面的位带操作是什么意思? 我也

Cortex-M3中GPIO位输出操作的几种方法

1.端口位设置/清除 在STM32F1xx系列芯片中,可对BSRR.BRR寄存器相应的位置1,以实现置位和清零操作,如: GPIOA->BSRR = (1<<3); // 设置端口A的位3为1 GPIOA->BRR = (1<<3); // 清除端口A的位3为0 在LPC17xx系列芯片中,可对FIOSET.FIOCLR寄存器相应的位置1,以实现置位和清零操作,如: LPC_GPIO2->FIOSET = (1<<3); // 设置端口2的位3为1 L

STM32F030系列实现仿位带操作

1.闲言 最近开发的时候,用到了STM32F030F4P6型号的单片机,它只有20个引脚,价格非常便宜,但是功能齐全:定时器.外部中断.串口.IIC.SPI.DMA和WWDG等等,应用尽有,非常适合用来做小设备.可是有个问题是,它是Cortex-M0内核的,不像M3,M4内核一样,可以支持位带操作(就是一位一位地操作,像80C51单片机一样),这就给程序移植或者开发带来了一点点小麻烦,因此我就利用C语言结构的位段操作,实现了个访位带操作,只是在效率可能会稍逊于真正的位带操作,但是代码上可以兼容,

STM32之GPIO端口位带操作

#ifndef __SYS_H #define __SYS_H #include "stm32f10x.h" //位带操作 //把“位带地址+位序号”转换别名地址宏 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) //把该地址转换成一个指针 #define MEM_ADDR(addr) *((volatil

Duanxx的STM32学习:GPIO的位带操作

支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写.在 CM3中,有两个区中实现了位带.其中一个是 SRAM 区的最低 1MB 范围,第二个则是片内外设区的最低 1MB 范围.这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自己的"位带别名区",位带别名区把每个比特膨胀成一个 32 位的字.当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的. 关于位带操作的博客说明有很多,这里主要将代码贴出来,并做详细的注释 /** ************

c#32位程序操作64位注册表

1 RegistryKey localKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64); 2 try 3 { 4 localKey = localKey.OpenSubKey( 5 @"SOFTWARE\Macromedia", true); 6 if (localKey != null) 7 { 8 localKey.DeleteSubKe

按位运算符操作

C语言中提供了6个位操作符.这些运算符只能作用于整形操作数,即只能作用于带符号或者无符号的char.short.int.long类型: & 按位与(AND) | 按位或(OR) ^ 按位异或(XOR) << 左移 >> 右移 ~ 按位取反(一元运算符) 下面以整形int为例进行说明(为了便于说明,设置二进制只有8位): #include "stdio.h" int main(int argc, char const *argv[]) { // 位操作符,

位带操作

1.位带区: 支持位带操作的地址区 2.位带别名:对别名地址的访问最终作用在位带区的访问(中途有地址映射) 3. 4. 5. 对于片上外设,映射关系参照上图关系修改即可. 6.举例: 建立一个把“位带地址+位序号”换成别名地址的宏,再建立一个把别名地址转换成指针类型的宏. 使用位带功能时,要访问的变量必须用volatile 来定义.(指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.)