Unix/C/C++--位域(位段)

1 介绍

有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用 0 和 1 表示足以,也就是用一个二进位。正是基于这种考虑,C语言又提供了一种叫做位域的数据结构。这在寄存器操作上用的较多些,如PLC行业modbus通信,位寄存器可能需要5个不需要一个字节。

2 结构体定义示例

typedef struct {
    char name:6;
    char city:2;
} DATA;
  • :后面的数字用来限定成员变量占用的位数。
  • C语言标准规定,位域的宽度不能超过它所依附的数据类型的长度。通俗地讲,成员变量都是有类型的,这个类型限制了成员变量的最大长度,:后面的数字不能超过这个长度。

3 支持类型

  • C语言标准还规定,只有有限的几种数据类型可以用于位域。
  • 在 ANSI C 中,这几种数据类型是 int、signed int 和 unsigned int(int 默认就是 signed int);
    到了 C99,_Bool 也被支持了。
  • 编译器在具体实现时都进行了扩展,额外支持了 char、signed char、unsigned char 以及 enum 类型,所以上面的代码虽然不符合C语言标准,但它依然能够被编译器支持。

4 位域存储

#include <stdio.h>

typedef struct {
    char name:6;
    char city:2;
} DATA;

int main()
{
    DATA data;
    printf("size of data: %ld\n", sizeof (data));
}

上述代码运行结果是1,结构体中位域成员紧邻存储占一个字节。

#include <stdio.h>

typedef struct {
    int name:6;
    int city:12;
    int year:5;
} DATA;

int main(){
    DATA data;
    printf("size of data: %ld\n", sizeof (data));
}

上述代码运行结果是4,结构体中位域成员紧邻存储,共占23bit,之所以为 4,而不是 3,是因为要将内存对齐到 4 个字节,以便提高存取效率。

4.1 位域是否跨字节

#pragma pack(1) 

// 叉车,2块IO板
typedef struct{
    uint8_t io1InputL:8;             //io板1,输入信号低8位,0~7
    uint8_t io1InputH:4;             //io板1,输入信号高4位,8~11
    uint8_t io1Output:8;             //io板1,输出信号 0~7
    uint8_t io2InputL:8;             //io板2,输入信号低8位,0~7
    uint8_t io2InputH:4;             //io板2,输入信号高4位,8~11
    uint8_t io2Output:8;             //io板2,输出信号 0~7
}LCD_IO_2_DATA;

其他结构体
#pragma pack()

sizeof(LCD_IO_2_DATA) windows下是6,linux是5,这说明编译不同,有的能跨字节有的不能跨字节。

#pragma pack(1) 

// 叉车,2块IO板
typedef struct{
    uint8_t io1InputL:8;             //io板1,输入信号低8位,0~7
    uint8_t io1InputH:4;             //io板1,输入信号高4位,8~11
    uint8_t io2InputH:4;             //io板2,输入信号高4位,8~11
    uint8_t io1Output:8;             //io板1,输出信号 0~7
    uint8_t io2InputL:8;             //io板2,输入信号低8位,0~7
    uint8_t io2Output:8;             //io板2,输出信号 0~7
}LCD_IO_2_DATA;

其他结构体
#pragma pack()

sizeof(LCD_IO_2_DATA) windows下是5,linux是5
在某些实现中,位字段不能跨越变量边界。仅当变量的总位数符合该变量的数据类型时,才能在变量中定义多个位字段。

5 伪指令#pragma pack

· 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
· 使用伪指令#pragma pack (),取消自定义字节对齐方式。

参考

1、C语言位域(位段)详解
2、请问 C语言里的 结构体中定义变量 后面的:是什么意思
3、C - Why #pragma pack(1) Consider 6-bit struct member as an 8-bit?
4、字节对齐(强制对齐以及自然对齐)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

worthsen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值