博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C语言中的结构体位域本质(bits field)与应用
阅读量:7224 次
发布时间:2019-06-29

本文共 3231 字,大约阅读时间需要 10 分钟。

hot3.png

基本形式

例如

struct bits{    uint32_t low:9;      //低9位    uint32_t middle: 13; //中间13位    uint32_t high: 10;   //高10位};

假设值为0xABCDEF09, 二进制为10101011110011011110111100001001

1010101111   0011011110111  100001001high(0x2AF)  middle(0X6F7)  low(0x109)

本质

本质就是位操作(移位/与/或)

对位域进行操作时, 并不是简单的赋值, 比如

struct bits{    uint32_t low:9;      //低9位    uint32_t middle: 13; //中间13位    uint32_t high: 10;   //高10位};struct bits b = {1, 2, 3};int x = b.middle;

它所对应的汇编如下

struct bits b = {1, 2, 3};  4004e1:	0f b7 45 f0          	movzwl -0x10(%rbp),%eax  4004e5:	66 25 00 fe          	and    $0xfe00,%ax  4004e9:	83 c8 01             	or     $0x1,%eax  4004ec:	66 89 45 f0          	mov    %ax,-0x10(%rbp)  4004f0:	8b 45 f0             	mov    -0x10(%rbp),%eax  4004f3:	25 ff 01 c0 ff       	and    $0xffc001ff,%eax  4004f8:	80 cc 04             	or     $0x4,%ah  4004fb:	89 45 f0             	mov    %eax,-0x10(%rbp)  4004fe:	0f b7 45 f2          	movzwl -0xe(%rbp),%eax  400502:	83 e0 3f             	and    $0x3f,%eax  400505:	0c c0                	or     $0xc0,%al  400507:	66 89 45 f2          	mov    %ax,-0xe(%rbp)	int x = b.middle;  40050b:	8b 45 f0             	mov    -0x10(%rbp),%eax  40050e:	c1 e8 09             	shr    $0x9,%eax  400511:	66 25 ff 1f          	and    $0x1fff,%ax  400515:	0f b7 c0             	movzwl %ax,%eax  400518:	89 45 fc             	mov    %eax,-0x4(%rbp)

上面的汇编可以看出, 编译器自动帮我们生成了各种移位/与/或相关的位操作.

如果不使用位域, 使用普通的结构体

struct bits{    uint32_t low;        uint32_t middle;     uint32_t high;  };struct bits b = {1, 2, 3};int x = b.middle;

对应的汇编是这样的

struct bits b = {1, 2, 3};  4004e1:	c7 45 f0 01 00 00 00 	movl   $0x1,-0x10(%rbp)  4004e8:	c7 45 f4 02 00 00 00 	movl   $0x2,-0xc(%rbp)  4004ef:	c7 45 f8 03 00 00 00 	movl   $0x3,-0x8(%rbp)	int x = b.middle;  4004f6:	8b 45 f4             	mov    -0xc(%rbp),%eax  4004f9:	89 45 ec             	mov    %eax,-0x14(%rbp)

就是简单的赋值操作

应用

压缩结构体大小这是网上所提到的最多的作用. 这其实是大材小用了(现在的各种设备内存, 也不差这几个字节). 最适合它的用途是协议解析. 比如aac的adts(总共7个字节), 它的定义是这样的

名称 比特数 说明
syncword 12 must be 0xFFF
ID 1 0 for mpeg-4, 1 for mpeg-2
layer 2 must be 00
protect 1
profile 2 0 for main profile, 1 for low complexity profile, 2 for scalable sampling rate profile, 3 reserved
frequency 4
private 1
channel 3 0:Defined in AOT Specifc Config, 1-6 for channel count, 7 for 8 channel
copy 1
home 1
copyright 1
copyright-start 1
frame-len 13
adts-fullness 11
blocks 2

现在定义一个位域结构体来解析它.

typedef union {    struct {        uint64_t padding:8;        uint64_t block:2;        uint64_t fullness: 11;        uint64_t frame_len:13;        uint64_t coypr_s:2;        uint64_t copy_home:2;        uint64_t channel:3;        uint64_t priv:1;        uint64_t freq:4;        uint64_t profile:2;        uint64_t protect:1;        uint64_t layer:2;        uint64_t id:1;        uint64_t syncword:12;    } bits;    uint64_t value;} adts;adts h;//7个字节的头.uint8_t bytes[7] = {0xFF, 0xF1, 0x5C, 0x80, 0x05, 0x7F, 0xFC};memcpy(&h.value, bytes, 7);//一般的系统都是小端, 上面这句拷贝之后, value的值,0x**FC7F05805CF1FF. (*号表示未知)//需要将其反转一下. 系统并没有ntoh64, 这是自定义的h.value = ntoh64(h.value);//...消息头的处理(略)printf("syncword: %d\n", h.bits.syncword);printf("channel: %d\n", h.bits.channel);

上面这段代码, 省略了大量的位操作代码, 全部由编译器代劳了.

转载于:https://my.oschina.net/u/2343729/blog/1838719

你可能感兴趣的文章
什么是 Angularjs
查看>>
Silverlight中为ComboBox设定当前选择项,真麻烦
查看>>
分析开源OpenERP与其他ERP系统实施是否方便!
查看>>
yum源配置
查看>>
PHP开发规范分享
查看>>
性能测试分层模型
查看>>
细数10个令人惊讶的NodeJS开源项目
查看>>
angularjs中的问题
查看>>
理解NSSComparisionResult 类型
查看>>
第二周作业
查看>>
Python Object Oriented
查看>>
Linux基础命令
查看>>
初入编程的新世界
查看>>
C++编译器详解(一)
查看>>
使用牙线
查看>>
部署Node.js项目(CentOS)
查看>>
Linux常用命令及vim的使用、vim常用插件(推荐)
查看>>
laravel 使用中间件解决跨域问题
查看>>
快速排序算法
查看>>
可控制左右切换的幻灯片轮换
查看>>