网站建设方案设计心得,三门峡做网站,阳江网约车,图片设计网站推荐目录 位与字节
位
比特
字节
对齐特性
位字段 位与字节
位
二进制数系统中#xff0c;每个0或1就是一个位(bit)#xff0c;位是数据存储的最小单位。其中8 bit就称为一个字节#xff08;Byte#xff09;。计算机中的CPU位数指的是CPU一次能处理的最大位数#xff0…目录 位与字节
位
比特
字节
对齐特性
位字段 位与字节
位
二进制数系统中每个0或1就是一个位(bit)位是数据存储的最小单位。其中8 bit就称为一个字节Byte。计算机中的CPU位数指的是CPU一次能处理的最大位数例如32位计算机的CPU一次最多能处理32位数据计算机中的CPU位数也成为机器字长和数据总线CPU与内部存储器之间连接的用于传输数据的线的根数的概念是统一的。
比特 1) 计算机专业术语是信息量单位是由英文BIT音译而来。二进制数的一位所包含的信息就是一比特如二进制数0101就是4比特。 2)二进制数字中的位信息量的度量单位为信息量的最小单位。数字化音响中用电脉冲表达音频信号“1”代表有脉冲“0”代表脉冲间隔。如果波形上每个点的信息用四位一组的代码表示则称4比特比特数越高表达模拟信号就越精确对音频信号信号还原能力越强。
字节
1字节byte 8 比特bit
注这个字节与比特的关系是规定的记住就好通用于任何场景容易混淆的是字长和字节字长指的是cpu一次性能够运算的数据的位数不同的计算机可能不一样但是字节这个概念是恒久不变的。
对齐特性
对齐指的是如何安排对象在内存中的位置。 _Alignof运算符给出了一个类型的对齐要求在关键字_Aligof后面的圆括号中写上类型名即可
size_t d_align _Alignof(float);假定d_align的值是4意思float类型对象的对齐要求是4。较大的对齐值被称为stricter或stronger,较小的值被称为weaker. 可以使用_Alignas说明符指定一个变量或类型的对齐值但是不应该要求该值小于基本对齐值。
_Alignas(double) char c1;
_Alignas(8) char c2;
unsigned char _Alignas(long double) c_arr[sizeof(long double)];注意 不同版本的要求不同有的要求_Alignas(type)说明符在类型说明符的后面有的在前面无论哪一种都能够识别。 位字段
位字段bit filed是C语言中一种存储结构不同于一般结构体的是它在定义成员的时候需要指定成员所占的位数。位字段是一个signed int或unsigned int类型变量中一组相邻的位C99和C11新增了Bool类型的位字段。位字段通过一个结构声明来建立该结构声明为每个字段提供标签并确定该字段的宽度。例如下面的声明建立了4个1位的字段
struct {unsigned autfd : 1;unsigned bldfc : 1;unsigned undln : 1;unsigned itals : 1;
} prnt;
根据该声明prnt包含了4个1位的字段。现在可以通过普通的结构成员运算符.单独给这些字段赋值 prnt.itals1;prnt.undln0;prnt.bldfc1;prnt.autfd0;
下面查看一下prnt的值 char str[33];int* valuereinterpret_castint*(prnt);itoa(*value,str,2);printf(%d %d %d %d\n, prnt.autfd,prnt.bldfc,prnt.undln,prnt.itals);printf(sizeof(prnt) %d\n,sizeof(prnt));printf(十进制: %d\n,prnt);printf(二进制: %032s\n,str);
输出的结果为 0 1 0 1 sizeof(prnt) 4 十进制 10 二进制 0000 0000 0000 0000 0000 0000 0000 1010
可以看出prnt的大小为4个字节unsigned int 或 signed int通过prnt的结构成员可以设置和访问某些bit位的值。 带有位字段的结构提供了一种记录设置的方便途径。许多设置如字体的粗体或斜体就是简单的二进制一。例如开或关、真或假。如果只需要使用1位就不需要使用整个变量。内含位字段的结构允许在一个存储单元中存储多个设置。 有时某些设置也有多个选择因此需要多位来表示。例如可以使用如下代码
struct{unsigned code1 : 2;unsigned code2 : 2;unsigned code3 : 8;
}prcode;
这里创建了两个2位的字段和一个8位的字段可以这样赋值 prcode.code10;prcode.code23;prcode.code3102;
但是要确保赋的值不超出字段可容纳的范围下面会说明当超出范围时会发生什么事情。
再次打印出prcode的内容 int* value_prcodereinterpret_castint*(prcode);itoa(*value_prcode,str,2);printf(%d %d %d\n,prcode.code1,prcode.code2,prcode.code3);printf(sizeof(prcode) %d\n,sizeof(prcode));printf(十进制: %d\n,prcode);printf(二进制: %032s\n,str);
打印结果如下 0 3 102 sizeof(prcode) 4 十进制1644 二进制0000 0000 0000 0000 0000 0110 0110 1100
可以看出prcode.code1对应于0-1比特位数值为00对应十进制为0 prcode.code1对应于2-3比特位数值为11对应十进制为3 prcode.code2对应于4-11比特位数值为0110 0110对应十进制为102。 因此一个字段可以对应于多个比特位且当使用结构字段赋值在可容纳的范围之内时变量可以记录正确的值。
这里再讨论一些需要注意的问题。首先是如果声明的总位数超过一个unsigned int类型的大小4 bytes时会发生什么事情结果是会用到下一个unsigned int类型的存储位置。一个字段不允许跨越两个unsigned int之间的边界。编译器会自动移动跨界的字段保持unsigned int的边界对齐。一旦发生这种情况第1个unsigned int中会留下一个未命名的“洞”。例如
struct{unsigned a : 4;unsigned b : 4;unsigned c : 4;unsigned d : 25;
}prlimit;
上面定义的位字段大小共37个bits超过了一个unsigned int的范围给prlimit的各结构成员赋值并使用下面代码打印出prlimit所存储的内容 prlimit.a0xF;prlimit.b0;prlimit.c0xF;prlimit.d0x1FFFFFF;char str_1[33];char str_2[33];int* value_1reinterpret_castint*(prlimit);int* value_2reinterpret_castint*(prlimit)1;itoa(*value_1,str_1,2);itoa(*value_2,str_2,2);printf(0x%x 0x%x 0x%x 0x%x \n,prlimit.a,prlimit.b,prlimit.c ,prlimit.d);printf(sizeof(prlimit) %d\n,sizeof(prlimit));printf(二进制 0~31位: %032s\n,str_1);printf(二进制 32~63位: %032s\n,str_2); 输出的结果如下 0xf 0x0 0xf 0x1ffffff sizeof(prlimit) 8 二进制 0-31位0000 0000 0000 0000 0000 1111 0000 1111 二进制 32-63位0000 0001 1111 1111 1111 1111 1111 1111
从输出的结果可以看出首先prlimit的大小为8个字节其次编译器强制prlimit.d字段发生边界对齐即prlimit.d位于第二个unsigned int上prlimit.c与prlimit.d之间会填充未命名的“洞”。
实际上我们也可以人为的在结构体当中设置未命名的字段宽度来进行填充。使用一个宽度为0的未命名的字段迫使下一个字段与下一个整数对齐
struct {unsigned field1 : 1;unsigned : 2;unsigned field2 : 1;unsigned : 0;unsigned field3 : 4;
} stuff; 使用下面的代码输出stuff的内容 stuff.field11;stuff.field21;stuff.field30xf;char str_1[33];char str_2[33];int *value_1reinterpret_castint*(stuff);int *value_2reinterpret_castint*(stuff)1;itoa(*value_1,str_1,2);itoa(*value_2,str_2,2);printf(sizeof(stuff) %d\n,sizeof(stuff));printf(二进制 0-31位: %032s\n,str_1);printf(二进制 32-63位: %032s\n,str_2);
输出的结果为 sizeof(stuff) 8 二进制 0-31位0000 0000 0000 0000 0000 0000 0000 1001 二进制 32-63位 0000 0000 0000 0000 0000 0000 0000 1111
也就是说在这里stuff.field1和stuff.field2之间有一个2位的空隙stuff.field3被强迫与下一个整数对齐存储到下一个unsigned int中。stuff的大小为8个字节。
最后讨论一个当赋值超出字段可容纳范围的问题。
struct {unsigned t1 : 2;unsigned t2 : 3;unsigned t3 : 4;
} test;int main(){test.t13;test.t30;test.t211;printf(%d %d %d\n,test.t1,test.t2,test.t3);int *valuereinterpret_castint*(test);char str[50];itoa(*value,str,2);printf(二进制%032s\n,str);return 0;} 输出的结果为 3 3 0 二进制0000 0000 0000 0000 0000 0000 0000 1111
上述代码中成员test.t2赋值的大小超出了容纳的范围。可以看到t2赋值为11(二进制是1011)结果输出的值是3二进制是011即截断了超出的部分。同时也可以看到超出的部分不会影响t3的值不同平台不一样网上有人说会覆盖超出的区域。
最后需要说明的是字段存储在一个int中的顺序取决于机器。在有些机器上存储的顺序是从左往右的而在另一些机器上是从右往左的。另外不同的机器中两个字段边界的位置也有区别。由于这些原因位字段通常都不容易移植。尽管如此有些情况却要用到这种不可移植的特性。例如以特定硬件设备所用的形式存储数据。