欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言位域(位段)

程序员文章站 2022-03-05 15:39:24
...

应用场景

有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用 0 和 1 表示足以,也就是用一个二进位。

位域实例

结构体定义

struct bs{
    unsigned int m;
    unsigned int n: 4;
    unsigned char ch: 6;
};

m:占用 4 个字节(Byte)的内存;

n:“:”后面的数字限定n占用的位数,不能再根据数据类型计算长度,n占用4位(Bit)内存;

ch:占用6位(Bit)内存。

#include <stdio.h>

int main(){
    struct bs{
        unsigned m;
        unsigned n: 4;
        unsigned char ch: 6;
    } a = { 0xad, 0xE, '$'};
   
 //第一次输出
    printf("%#x, %#x, %c\n", a.m, a.n, a.ch);
    
//更改值后再次输出
    a.m = 0xb8901c;
    a.n = 0x2d;
    a.ch = 'z';
 //第二次输出 
printf("%#x, %#x, %c\n", a.m, a.n, a.ch);

    return 0;
}

运行结果:

0xad, 0xe, $
0xb8901c, 0xd, :

对于 n 和 ch,第一次输出的数据是完整的,第二次输出的数据是残缺的。
第一次输出:n、ch 的值分别是 0xE、0x24('$' 对应的 ASCII 码为 0x24),换算成二进制是 1110、10 0100,都没有超出限定的位数,能够正常输出。
第二次输出:n、ch 的值变为 0x2d、0x7a('z' 对应的 ASCII 码为 0x7a),换算成二进制分别是 10 1101、111 1010,都超出了限定的位数。超出部分被直接截去,剩下 1101、11 1010,换算成十六进制为 0xd、0x3a(0x3a 对应的字符是 :)。
 

C语言标准规定

1)位域的宽度不能超过它所依附的数据类型的长度。通俗地讲,成员变量都是有类型的,这个类型限制了成员变量的最大长度,“:”后面的数字不能超过这个长度。

2)只有有限的几种数据类型可以用于位域。在 ANSI C 中,这几种数据类型是 int、signed int 和 unsigned int(int 默认就是 signed int);到了 C99,_Bool 也被支持了。

3)编译器在具体实现时都进行了扩展,额外支持了 char、signed char、unsigned char 以及 enum 类型,所以上面的代码虽然不符合C语言标准,但它依然能够被编译器支持。

相关标签: 代码学习