Byte alignment and protocol parsing

#pragma pack(show) //显示当前内存对齐的字节数,编辑器默认8字节对齐

#pragma pack(n) //设置编辑器按照n个字节对齐,n可以取值1,2,4,8,16

#pragma pack(push) //将当前的对齐字节数压入栈顶,不改变对齐字节数

#pragma pack(push,n) //将当前的对齐字节数压入栈顶,并按照n字节对齐

#pragma pack(pop) //弹出栈顶对齐字节数,不改变对齐字节数

#pragma pack(pop,n) //弹出栈顶并直接丢弃,按照n字节对齐

前言

擅长用字节对齐可以节省脑细胞,提高代码可读性,这里为大家展示下配置字节对齐来高效的解析报文。

示例场景

如下报文格式

字节
类型
功能
说明

CMD

0x10

SCMD

0x10

2 1 1 4 1 4 [4] …

U16 U8 U8 Float U8 Float [Float] …

Type Chnnl State Value Num AD1 [AD2] …

数据 1 的测量状态和测量值: Type:表示数据类型,详见附录 B。 Chnnl:表示数据通道 State:表示数据状态 b7:数值有效/无效:1-有效,0-无效 b6b3:为 0,预留 b2b0:数值单位,详见附录 B。 Value:表示数据测量值 Num:电参量个数 AD1:对应实测电参量 1 AD2:对应实测电参量 2 …:对应实测点参量 n

[2] [1] [1] [4] [1] [4] [4] …

[U16] [U8] [U8] [Float] [U8] [Float] [Float] …

Type Chnnl State Value Num AD1 [AD2] …

数据 2 的测量状态和测量值:

数据 n 的测量状态和测量值:

对应报文可以如下设计

#pragma pack(1)
typedef struct _PROTOCOL_0X1010
{
    uint16_t type;
    uint8_t chnnl;
    uint8_t state;
    float value;
    uint8_t num;
    float AD[0];
} protocol_0x1010_t;

#pragma pack()

关键信息解释:

  1. #pragma pack(1)#pragma pack() 是成对出现的,否则将影响后续其它结构体的对齐问题,这里进行1字节对齐,牺牲了MCU的效率换来的是可读取,而牺牲的效率我认为比我们手动操作强的多。

  2. AD[0] 柔性数组,在结构体中可以方便对后续数据的读取工作,AD多个参数便可之间访问,避免类型转换问题。

使用示例

        uint32_t i = 0;
        while (i <= pfrm->length)
        {
            protocol_0x1010_ptr data_ptr = (protocol_0x1010_ptr) & (pfrm->text[i]);
            uint8_t sensor_idx = sensor_info_find_idx(data_ptr->type);
            if (sensor_idx < DEV_MAX_ID)
            {
                sensor_value_t *sensor_value_ptr = &m_sensor_module.value[sensor_idx];
                sensor_value_ptr->status.online = (data_ptr->state & 0x80) != 0;
                sensor_value_ptr->tick = tick_cur;
                sensor_value_ptr->meas = data_ptr->value;
                sensor_value_ptr->raw = data_ptr->AD[0];
                i += sizeof(protocol_0x1010_t) + data_ptr->num * sizeof(float);
            }

        }

Last updated