15.位操作

news2024/9/23 21:31:38

文章目录

  • 位操作
    • 15.1二进制数、位和字节
      • 15.1.1二进制整数
      • 15.1.2有符号整数(?)
      • 15.1.3二进制浮点数
        • 1.二进制小数
        • 2.浮点数表示法
    • 15.2其他进制数
      • 15.2.1八进制
      • 15.2.2十六进制
    • 15.3C按位运算符
      • 1.二进制反码或按位取反:~
      • 2.按位与:&
      • 3.按位或:|
      • 4.按位异或:^
      • 15.3.2用法:掩码
      • 15.3.3用法:打开位(设置位)
      • 15.3.4用法:关闭位(清空位)
      • 15.3.5用法:切换位
      • 15.3.6用法:检查位的值
      • 15.3.7移位运算符
        • 1.左移:<<
        • 2.右移:>>
        • 3.用法:移位运算符
    • 15.4位字段
      • 15.4.1位字段示例
      • 15.4.2位字段和按位运算符
    • 15.5对齐特性(C11)

位操作

15.1二进制数、位和字节

十进制数2157可以写成:2 x 103 + 1 x 102 + 5 x 101 + 7 x 100,因为这种数学数字的方法是基于10的幂,所以称以10为基底书写2157。
计算机的位只能被设置为0或1,关闭或打开。因此,计算机适用基底为2的数制系统,即二进制数。二进制中的2和十进制中的10作用相同。例如,二进制数1101可以表示为:1 x 23 + 1 x 22 + 0 x 21 + 1 x 20,结果为13。

15.1.1二进制整数

通常,1字节包含8位。可以从左往右给这8位分别编号为7~0.在1字节中,编号是7的位被称为高阶位,编号是0的位被称为低阶位。每1位的编号对应2的相应指数。

在这里插入图片描述

该字节能表示的最大数字是把所有位都设置为1,即11111111。这个二进制数的值是:128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255。而该字节最小的二进制数是00000000,其值为0。因此,1字节可以储存0~255范围内的数字,总共256个值。或者,通过不同的方式解释位组合,程序可以用1字节储存-128~+127范围内的整数,总共还是256个值。

15.1.2有符号整数(?)

如何表示有符号整数取决于硬件,而不是c语言。也许表示有符号数最简单的方式是用1位(如,高阶位)储存符号(原码),只剩下7位表示数字本身(假设储存在1字节中)。用这种符号量表示法,10000001表示-1,00000001表示1.因此,其表示范围是-127~+127
这种方法的缺点是有两个0:+0(00000000)和-0(10000000)。这很容易混淆,而且用两个位组合来表示一个值也有些浪费。
二进制补码方法避免了这个问题,是当今最常用的系统。以1字节为例,二进制补码用1字节中的后7位表示0~127,高阶位设置为0。目前,这种方法和符号量的方法相同。另外,如果高阶位是1,表示的值为负。这两种方法的区别在于如何确定负值。从一个9位组合100000000(256的二进制形式)减去一个负数的位组合,结果是该负值的量。例如,假设一个负值的位组合是10000000,作为一个无符号字节,该组合为表示128;作为一个有符号值,该组合表示负值(编码是7的位为1),而且值为100000000-10000000,即1000000(128)[注:这儿的位运算结果应该是少个0]。因此,该数是-128(在符号量表示法中,该位组合表示-0)。类似的,10000001是-127,11111111是-1。该方法可以表示-128~+127范围内的数。
要得到一个二进制补码的相反数,最简单的方法是反转每一位(即0变为1,1变为0),然后加1。因为1是00000001,那么-1则是11111110+1,或11111111。这与上面的介绍一致。
二进制反码方法通过反转位组合中的每一位形成一个负数。例如,00000001是1,那么11111110是-1。这种方法也有一个-0:11111111。该方法能表示-127~+127之间的数。

15.1.3二进制浮点数

浮点数分两部分储存:二进制小数和二进制指数。

1.二进制小数

一个普通的浮点数0.527,表示为:5/10 + 2/100 + 7/1000。从左往右,各分母都是10的递增次幂。在二进制小数中,使用2的幂作为分母,所以二进制小数.101表示为:1/2 + 0/4 + 1/8,最后的结果为0.625。
许多分数(如,1/3)不能用十进制表示法精确地表示。与此类似,许多分数也不能用二进制表示法准确地表示。实际上,二进制表示法只能精确地表示多个1/2的幂的和。因此,3/4和7/8可以精确地表示为二进制小数,但是1/3和2/5却不能。

2.浮点数表示法

为了在计算机中表示一个浮点数,要留出若干位(因系统而异)储存二进制分数,其他位储存指数。一般而言,数字的实际值是由二进制小数乘以2的指定次幂组成。例如,一个浮点数乘以4,那么二进制小数不变,其指数乘以2,二进制分数不变。如果一个浮点数乘以一个不是2的幂的数,会改变二进制小数部分,如有必要,也会改变指数部分。

15.2其他进制数

15.2.1八进制

八进制是指八进制记数系统。该系统基于8的幂,用0~7表示数字。例如,八进制数451(在c中写作0451)表示为:4 x 82 + 5 x 81+ 1 x 80 = 297(十进制)。
了解八进制的一个简单的方法是,每个八进制位对应3个二进制位。

在这里插入图片描述

这种关系使得八进制与二进制之间的转换很容易。例如,八进制数0377的二进制形式是11111111。即,用111代替最后一个7,再用111代替倒数第2个7,最后用011代替3,并舍去第1位的0。这表明比0377大的八进制要用多个字节表示。这是八进制唯一不方便的地方:一个3位的八进制数可能要用9位二进制数来表示。注意,将八进制数转换为二进制形式时,不能去掉中间的0。例如,八进制数0173的二进制形式是01111011,不是0111111。

15.2.2十六进制

十六进制是指十六进制记数系统。该系统基于16的幂,用0~15表示数字。但是,由于没有单独的数表示10~15,所以用A~F来表示。例如,十六进制数A3F(在c中写作0xA3F)表示为:10 x 162 + 3 x 161 + 15 x 160 = 2623(十进制)。
每个十六进制位都对应一个4位的二进制数(即4个二进制位),那么两个十六进制位恰好对应一个8位字节。第1个十六进制位表示前4位,第2个十六进制位表示后4位。因此,十六进制很适合表示字节值。

在这里插入图片描述

15.3C按位运算符

4个按位逻辑运算符都用于整型数据,包括char。这些操作都是针对每一个位进行,不影响它左右两边的位。

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

一元运算符~把1变为0,把0变为1。假设val的类型是unsigned char,已被赋值为2。在二进制中,00000010表示2。那么,~val的值是11111101,即253。

2.按位与:&

二元运算符&通过逐位比较两个运算对象,生成一个新值。对于每个位,只有两个运算对象中相应的位都为1时,结果才为1。因此,10010011 & 00111101结果为:00010001。

3.按位或:|

二元运算符|,通过逐位比较两个运算对象,生成一个新值。对于每个位,如果两个运算对象中相应的位只要有一个为1,结果就为1。因此,10010011 | 00111101结果为:10111111。

4.按位异或:^

二元运算符^逐位比较两个运算对象。对于每个位,如果两个运算对象中相应的位一个为1(但不是两个为1),结果为1。因此,10010011 ^ 00111101结果为:10101110。

15.3.2用法:掩码

按位与运算符常用于掩码。所谓掩码指的是一些设置为开(1)或关(0)的位组合。要明白称其为掩码的原因,先来看通过&把一个量与掩码结合后发生什么情况。例如,假设定义符号常量MASK为2(即,二进制形式为00000010):

flags = flags & MASK;

flags中除1号位以外的所有位都设置为0,因为使用按位与运算符(&)任何位与0组合都得0。这个过程叫作使用掩码,因为掩码中的0隐藏了flags中相应的位。

在这里插入图片描述

按位与的一种常见用法:

// 0xff的二进制形式11111111,八进制形式是0377。
ch &= 0xff;	/* 或者ch &= 0377 */

这个掩码保持ch中最后8位不变,其他位都设置为0。无论ch原来是8位、16位或是其他更多位,最终的值都被修改为1个8位字节。

15.3.3用法:打开位(设置位)

有时,需要打开一个值中的特定位,同时保持其他位不变。

// 把flags中的1号位设置为1,且其他位不变。
flags = flags | MASK;

使用|运算符,任何位与0组合,结果都为本身;任何位与1组合,结果都为1

15.3.4用法:关闭位(清空位)

和打开特定的位类似,有时也需要在不影响其他位的情况下关闭指定的位。假设要关闭变量flags中的1号位。同样,MASK只有1号位为1(即,打开)。可以这样做:

flags = flags & ~MASK;

使用&,任何位与1组合都得本身;任何位与0组合都得0

15.3.5用法:切换位

切换位指的是打开已关闭的位,或关闭已打开的位。可以使用按位异或运算符(^)切换位。也就是说,假设b是一个位,如果b为1,则1^b为0;如果b为0,则1^b为1。另外,无论b为1还是0,0^b均为b。因此,如果使用^组合一个值和一个掩码,将切换该值与MASK为1的位相对应的位,该值与MASK为0的位相对应的位不变。

flags = flags ^ MASK;

15.3.6用法:检查位的值

有时,需要检查某位的值。例如,flags中1号位是否被设置为1。不能直接比较flagsMASK

// 即使flags的1号位为1,其他位的值会导致比较结果为假。
if (flags == MASK) {
	puts("Wow!");	/* 不能正常工作 */
}

// 必须覆盖flags中的其他位,只用1号位和MASK比较:
if ((flags & MASK) == MASK) {
	puts("Wow!");
}

为了避免信息漏过边界,掩码至少要与其覆盖的值宽度相同。

15.3.7移位运算符

1.左移:<<

左移运算符(<<)将其左侧运算对象每一位的值向左移动其右侧运算对象指定的位数。左侧运算对象移出左末端位的值丢失,用0填充空出的位置。例如,10001010 << 2的结果为:00101000。

2.右移:>>

右移运算符(>>)将其左侧运算对象每一位的值向右移动其右侧运算对象指定的位数。左侧运算对象移出右末端位的值丢失。对于无符号类型,用0填充空出的位置;对于有符号类型,其结果取决于机器。空出的位置可用0填充,或者用符号位(即,最左端的位)的副本填充:

(10001010) >> 2	// 表达式,有符号值。
(00100010)	// 在某些系统中的结果值
(10001010) >> 2	// 表达式,有符号值。
(11100010)	// 在另一些系统上的结果值

(10001010) >> 2	// 表达式,无符号值。
(00100010)	// 所有系统都得到该结果值

3.用法:移位运算符

移位运算符针对2的幂提供快速有效的乘法和除法:

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

这些移位运算符类似于在十进制中移动小数点来乘以或除以10。

移位运算符还可用于从较大单元中提取一些位:

// 假设用一个unsigned long类型的值表示颜色值,低阶位字节储存红色的强度,
// 下一个字节储存绿色的强度,第3个字节储存蓝色的强度。随后希望把每种颜色的
// 强度分别储存在3个不同的unsigned char类型的变量中:
#define BYTE_MASK 0xff
unsigned long color = 0x002a162f;
unsigned char blue, green, red;
red = color & BYTE_MASK;
// 使用右移运算符将8位颜色值移动至低阶字节,然后使用掩码技术把低阶字节赋给指定的变量。
green = (color >> 8) & BYTE_MASK;
blue = (color >> 16) & BYTE_MASK;

15.4位字段

操控位的第2种方法是位字段。位字段是一个unsigned intunsigned int类型变量中的一组相邻的位(C99和C11新增了_Bool类型的位字段)。位字段通过一个结构声明来建立,该结构声明为每个字段提供标签,并确定该字段的宽度。

// 建立一个4个1位的字段:
struct {
	unsigned int autfd: 1;
	unsigned int bldfc: 1;
	unsigned int undln: 1;
	unsigned int itals: 1;
} prnt;

// 由于每个字段恰好为1位,所以只能为其赋值1或0。变量prnt被储存在int
// 大小的内存单元中,但是在这里只使用了其中的4位。
prnt.itals = 0;
prnt.undln = 1;

带有位字段的结构提供一种记录设置的方便途径。许多设置(如,字体的粗体或斜体)就是简单的二选一。如果只需要使用1位,就不需要使用整个变量。内含位字段的结构允许在一个存储单元中储存储存多个设置。
有时,某些设置也有多个选择,因此需要多位来表示。这没问题,字段不限制1位大小:

// 创建了两个2位的字段和一个8位的字段:
struct {
	unsigned int code1: 2;
	unsigned int codes: 2;
	unsigned int code3: 8;
} prcode;

// 要确保所赋的值不超出字段可容纳的范围
prcode.code1 = 0;
prcode.code2 = 3;
prcode.code3 = 102;

如果声明的总位数超出了一个unsigned int类型的大小会怎么样,此时,会用到下一个unsigned int类型的存储位置。一个字段不允许跨越两个unsigned int之间的边界。编译器会自动移动跨界的字段,保持unsigned int的边界对齐。一旦发生这种情况,第1个unsigned int中会留下一个未命名的洞。
可以用未命名的字段宽度填充未命名的洞。使用一个宽度为0的未命名字段迫使下一个字段与下一个整数对齐:

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

字段储存在一个int中的顺序取决于机器。在有些机器上,存储的顺序是从左往右,而在另一些机器上,是从右往左。另外,不同的机器中两个字段边界的位置也有区别。由于这些原因,位字段通常都不容易移植。尽管如此,有些情况却要用到这种不可移植的特性。例如,以特定硬件设备所用的形式储存数据。

15.4.1位字段示例

// 一个字节储存方框内部(透明和填充色)的属性,一个字节储存方框边框的属性,
// 每个字节中的空隙用未命名字段填充。加上未命名的字段,该结构共占用16位。
// 如果不使用填充,该结构占用10位。
struct box_props {
	bool opaque: 1;
	unsigned int fill_color: 3;
	unsigned int: 4;
	bool show_border: 1;
	unsigned int border_color: 3;
	unsigned int border_style: 2;
	unsigned int: 2;
};

需要注意的是,c以unsigned int作为位字段结构的基本布局单元。因此,即使一个结构唯一的成员是1位字段,该结构的大小也是一个unsigned int类型的大小,即32位。

15.4.2位字段和按位运算符

在同类型的编程问题中,位字段和按位运算符是两种可替换的方法,用哪种都可以。例如,使用和unsigned int类型大小相同的结构储存图形框的信息。也可以使用unsigned int变量储存相同的信息。如果不想用结构成员表示法来访问不同的部分,也可以使用按位运算符来操作。一般而言,这种方法比较麻烦。

15.5对齐特性(C11)

C11的对齐特性比用位填充字节更自然,它们还代表了c在处理硬件相关问题上的能力。在这种上下文中,对齐指的是如何安排对象在内存中的位置。例如,为了效率最大化,系统可能要把一个double类型的值储存在4字节内存地址上,但却允许把char储存在任意地址。大部分程序员都对对齐不以为然。但是,有些情况又受益于对齐控制。例如,把数据从一个硬件位置移到另一个位置,或者调用指令同时操作多个数据项。
_Alignof运算符给出一个类型的对其要求,在关键字_Alignof后面的圆括号中写上类型名即可:

// 假设d_align的值是4,意思是float类型对象的对齐要求是4。
// 也就是说,4是储存该类型值相邻地址的字节数。
size_t d_align = _Alignof(float);

一般而言,对齐值都应该是2的非负整数次幂。较大的对齐值被称为stricterstronger,较小的对齐值被称为weaker
可以使用_Alignas说明符指定一个变量或类型的对齐值。但是,不应该要求该值小于基本对齐值。例如,如果float类型的对齐要求是4,不要请求其对齐值是1或2.该说明符用作声明的一部分,说明符后面的圆括号内包含对齐值或类型:

_Alignas(double) char c1;
_Alignas(8) char c2;
unsigned char _Alignas(long double) c_arr[sizeof(long double)];

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/57222.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTML+CSS网页设计期末课程大作业 【茶叶文化网站设计题材】web前端开发技术 web课程设计 网页规划与设计

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

[附源码]计算机毕业设计springboot校园代取快递系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

dreamweaver作业静态HTML网页设计——我的家乡海南旅游网站

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

LIO-SAM源码解析(五):mapOptmization.cpp

1. 代码流程 1.1. extractSurroundingKeyFrames() 1.2. scan2MapOptimization() 这个函数主要就是进行帧到地图的匹配&#xff0c;通过点到面、点到线的距离距离最小作为优化目标。LOAM中雅阁比矩阵推导其实还是过于复杂了&#xff0c;可以使用进行误差扰动来计算雅阁比矩阵&a…

Unity事件函数的执行顺序

事件函数的执行顺序 脚本生命周期流程图 场景加载时 这些函数在场景开始时被调用&#xff08;场景中的每个对象一次&#xff09;Awake&#xff1a;此函数总是在任何 Start 函数之前以及在预制件被实例化之后调用&#xff08;如果 GameObject 在启动期间处于非活动状态&#xf…

好家伙!阿里并发核心编程宝典(2022版)一夜登顶Github热榜第三

不知道大家今年的金九银十是否有出去面试过&#xff1f;有出去面试的朋友肯定深有感受&#xff0c;像我们刚入行那会面试的加分项现在卷得已经成为了面试的基础题&#xff08;手动狗头&#xff09;。其中最典型的就属这个Java并发编程了。之前一般只有大厂才会有高并发编程相关…

[附源码]Python计算机毕业设计Django基于vuejs的爱宠用品销售app

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

three.js之模型

文章目录简介网格模型旋转平移缩放方法平移旋转属性缩放位置平移旋转复制与克隆复制方法克隆方法注意专栏目录请点击 简介 我们常见的模型有点模型&#xff0c;线模型、网格模型他们的分类如下 点模型 Points对应的材质为点材质PointsMaterial 线模型 Line 线渲染模式Line…

AIGC独角兽官宣联手,支持千亿大模型的云实例发布,“云计算春晚”比世界杯还热闹...

梦晨 发自 凹非寺量子位 | 公众号 QbitAI现在AI最火的方向是什么&#xff1f;那必须是AIGC&#xff08;AI Generated Content&#xff0c;利用人工智能技术来生成内容&#xff09;。AIGC最火的公司是谁&#xff1f;莫过于开源AI作画模型Stable Diffusion背后的StabilityAI。对于…

【数学】焦点弦定理(?)

因为和焦点弦相关的定理太多&#xff0c;我不会把哪一个公式叫成这样的名字&#xff0c;但百度搜出来就是这个名字 如图&#xff0c;椭圆中焦点弦 AB,∣FB∣k∣FA∣(k>0)AB, |FB|k|FA|(k>0)AB,∣FB∣k∣FA∣(k>0) &#xff0c;求 ABABAB 倾斜角的余弦值 cos⁡θ\cos\t…

Anntec ZKUXFT XT2 FGPA卡DPDK使用方法

1. 建议环境 CPU Architecture x86_64、aarch64 CPU MHz&#xff1a; 2000以上 Memory 每个node空闲内存超过2G 硬盘 剩余空间大于100M OS Ubuntu,centos,银河麒麟&#xff0c;UOS等Linux …

亚马逊 CTO Werner Vogels:2023 年及未来五大技术趋势预测

近年来&#xff0c;几次全球性危机占据了我们的日常生活&#xff0c;因此看看我们是否可以利用技术来解决这些棘手的人类问题。如今&#xff0c;我们可以从很多互联设备获取数据&#xff0c;例如&#xff1a;可穿戴设备、医疗设备、环境传感器、视频捕捉设备等&#xff0c;数据…

DiffKit -- 世上最牛且开源的表数据对比工具

DiffKit -- 世上最牛且开源的表数据对比工具1. DiffKit Introduction1.1 Introduction1.2 Compatibility1.3 Download2. Quick Start3. User Guide4. Code5. Waken1. DiffKit Introduction 1.1 Introduction DiffKit Website: http://www.diffkit.org/index.html. 1.2 Compati…

excel数据分析

目录1. 对比分析2. 结构分析3. 分布分析3.1 VLooKup模糊匹配功能进行分组3.2 数据透视表进行数值型数据分组1. 对比分析 2. 结构分析 3. 分布分析 定义&#xff1a;根据分析目的&#xff0c;将数值型数据进行等距或不等距的分组 消费分布分析收入分布分析年龄分布分析 定量…

[附源码]Python计算机毕业设计Django交通事故档案管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

思派健康通过上市聆讯:半年亏损约35亿元,马旭广为董事长

12月2日&#xff0c;思派健康科技有限公司&#xff08;下称“思派健康”&#xff09;在港交所递交了聆讯后资料集。这代表着&#xff0c;思派健康已经通过港交所上市聆讯&#xff0c;将很快发行并在港交所IPO。 招股书显示&#xff0c;思派健康目前经营三条业务线&#xff0c;…

[附源码]JAVA毕业设计家庭理财管理系统(系统+LW)

[附源码]JAVA毕业设计家庭理财管理系统&#xff08;系统LW&#xff09; 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术…

RTK-RTD-SBAS-WAAS-PPP-PPK-WADGPS

1. RTD&#xff1a;英文全称Real Time Differential&#xff0c;中文意思是实时动态码相位差分技术。工作方法是基准站将伪距&#xff08;或者坐标&#xff09;修正值&#xff08;差分值&#xff09;发给用户接收机&#xff0c;用户接收机根据差分值与本身的观测值算出精确位置…

事业编招聘:共青团市委所属事业单位2022年公开招聘公告

杭州青少年活动中心为共青团杭州市委所属财政适当补助事业单位&#xff0c;因工作需要&#xff0c;公开招聘事业编制工作人员3名。根据《关于贯彻落实国家人事部〈事业单位公开招聘人员暂行规定〉的实施办法》&#xff08;杭人政〔2006〕5号&#xff09;和《杭州市事业单位公开…

计网个人作业03

R14. True or false? a a. Suppose Host A is sending a large file to Host B over a TCP connection. If the sequence number for a segment of this connection is m, then the sequence number for the subsequent segment will necessarily be m 1. 假设主机A通过一…