《c primer plus》c语言学习笔记整理(十五)-位操作

第十五章 位操作

1.二进制数、位、字节
(1)二进制整数
c语言用字节表示储存系统字符集所需的大小,所以c字节可能是8位,9位,16位或其他值。
不过描述存储器芯片和数据传输率中所用的字节指的是8位字节。
(2)有符号整数
1)如何表示有符号整数取决于硬件,而不是c语言
2)二进制补码是当今最常用的系统
3)二进制反码:通过反转位组合中的每一位形成一个负数。
4)要得到一个二进制补码数的相反数,最简单的方法是反转每一位,然后加1.
(3)二进制浮点数
浮点数分为两部分储存:二进制小数和二进制i指数
1)二进制小数:二进制表示法只能精确地表示多个1/2的幂的和,许多分数不能用十进制表示法精确地表示,许多分数也不能用二进制表示法准确地表示,二进制小数中,使用2的幂作为分母(3/4,7/8可以精确表示,1/3和2/5)
2)浮点数表示法:留出若干位(因系统而异)储存二进制分数,其他位储存指数,一般而言数字的实际值是由二进制小数乘以2的指定次幂组成。
2.其他进制数
(1)八进制
1)每个八进制位对应3个2进制位
2)用0-7表示数字,基于8的幂
3)八进制唯一不方便的地方:一个3位的八进制数可能要用9位二进制数表示
(2)十六进制
3.c按位运算符
(1)按位逻辑运算符
针对每一个位进行,不影响它左右两边的位,4个按位运算符都用于整型数据,包括char。
1)二进制反码或按位取反:~,该运算符不会改变变量的值,但是创建了一个新值可以赋值给其他变量。
2)按位与&:通过逐位比较两个运算符号,生成一个新值。对于每个位,只有两个运算对象中相应的位都为1的时候,结果才为1.(位上都为真)
3)按位或|:一个位为真,结果就为真
4)按位异或:两个运算对象中相应的一个位为真且不是两个同为1,那么结果为真。
(2)用法:掩码
按位与运算符(&)常用于掩码,掩码是指的是一些设置为开或关的位组合,掩码中的0看作不透明,1看作透明的。(某个位的值不变,其余位用0掩盖)
(3)用法:打开位(设置位)

flags = flags I MASK;

使用按位或运算符(|),任何与0组合,结果都为本身,任何与1结合,结果都为1.
(4)用法:关闭位(清空位)

flags = flags & ~MASK;

(5)用法:切换位

flags = flags  MASK;
flags ^= MASK;

打开已关闭的位,或关闭已打开的位,使用按位异或运算符(^)切换位。
(6)用法:检查位的值
1)用掩码覆盖变量的其他位,只用需要检查位的值来与MASK比较:

if ((flags & MASK) == MASK)
	puts ("Wow!") ;

2)按位运算符的优先级比==低,所以必须加上括号。
3)为了避免信息漏过边界,掩码至少要和其覆盖的值的宽度相同。
(7)移位运算符
1)左移:<<,移出左末端位的值丢失,用0填充空出的位置:该操作产生一个新值,但是不改变其运算对象。

(10001010) << 2 //表达式
(001010)		// 结果值

2)右移:>>移出右末端位的值丢失。对于无符号类型,用0填充空出的位置,对于有符号类型,结果取决于机器。空出的位置可用0填充,或者用符号位(即:最左端的位)的副本填充

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

3)用法:针对2的幂提供快速有效的乘法和除法
类似于在十进制中移动小数点来乘以或者除以10.

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

4.位字段
(1)位字段示例
1)位字段是一个signed int或unsigned int类型变量中的一组相邻的位(C99和C11新增了_Bool类型的位字段)。
2)通过一个结构声明建立,该结构声明为每个字段提供标签,并确定该字段的宽度。
3)带有位字段的结构提供一种记录设置的方便途径,许多设置(如,字体的粗体或斜体)就是简单的二选一,有时候有些设置也需要多个选择,因此需要多位来表示。
4)要确保赋值不超过字段可容纳的范围
5)如果声明的总位数超过了一个unsigned int类型的大小,会用到下一个unsigned int类型的存储位置。
6)一个字段不允许跨越两个unsigned int之间的边界,编译器会自动移动跨界的字段,保持unsigned int的边界对齐。第一个unsigned int中会留下洞,可以用未命名的字段宽度“填充”未命名的洞,使用一个宽度为0的未命名字段迫使下一个字段与下一个整数对齐。

struct {
	unsigned int fieldl: 1;
	unsigned int:2;
	unsigned int field2:1;
	unsigned int:0;
	unsigned int field3:1;
}stuff;

fields3将储存在下一个unsigned int中。
7)字段储存在一个int中的顺序取决于机器,在有些机器上是从左往右,有些机器上是从右往左。不同机器中两个字段边界的位置也有区别,由于这些原因,位字段通常不容易移植。
8)通常把位字段当作一种更紧凑存储数据的方式。
9)c以unsigned int作为位字段结构的基本布局单元,即使一个结构唯一的成员是1位字段,该结构的大小也是一个unsigned int类型的大小。
5.对齐特性
C11的对齐特性比用位填充字节更自然,他们代表了C在处理硬件相关问题上的能力,对齐指的是如何安排对象在内存中的位置。
(1)对齐方式:

size t d align = Alignof (float);

_Alignof运算符给出一个类型的对齐要求,在关键字_Alignof后面的圆括号写上类型名即可
(2)一般而言对齐值都应该是2的非负整数次幂。较大的对齐值被称为stricker或stronger,较小的对齐值被称为weaker。
(3)可以使用_Alignas说明符指定一个变量或类型的对齐值,但是不应该要求该值小于基本对齐值。该说明符作为声明的一部分,说明符后面的圆括号包含对齐值或类型。
(4)在程序中包含stdalign.h头文件,就可以把alignas和alignof分别作为_Alignoas和_Alignof的别名,这样可以与C++关键字匹配。
(5)C11在stdlib。h中添加了一个新的内存分配函数,用于对齐动态分配的内存,原型如下:

void *aliqned alloc(size t aliqnment, size t size);

参数1代表指定的对齐,参数2代表所需的字节数,其值为第一个参数的倍数,与其他内存分配函数一样,要使用free()函数释放之前分配的内存。
总结:通常,使用位字段、对齐功能特性的程序,仅限于特定的硬件平台或操作系统,而且设计为不可移植的。

你可能感兴趣的:(C语言)