




已阅读5页,还剩60页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
此文档收集于网络,如有侵权,请联系网站删除嵌入式系统程序可移植性设计及性能优化之一宏定义设计Sailor_forever sailing_9806163.com 转载请注明/sailor_8318/archive/2008/07/16/2663254.aspx 【摘要】本节介绍了嵌入式系统程序设计中采用宏定义进行常量定义的必要性。说明了宏常量定义的基本规则以及如何采用依赖关系定义宏常量来保证其可移植性和裁减性。最后介绍了如何利用宏定义实现掩码偏移量等来高效的进行位操作。 【关键词】嵌入式,可移植性,宏定义,依赖关系,掩码,偏移量,位操作 1 宏定义设计. - 1 -1.1 为何要采用宏定义?. - 1 -1.2 宏定义的基本规则. - 1 -1.3 依赖关系定义宏改善移植性. - 1 -1.4 通过偏移量和掩码进行位操作. - 2 - 1 宏定义设计1.1 为何要采用宏定义?在程序设计过程中,对于经常使用的一些常量,如果将它直接写到程序中去,一旦常量的数值发生变化,就必须逐个找出程序中所有的常量,并逐一进行修改,这样必然会降低程序的可维护性。因此,应尽量通过预处理命令方式将常量定义为特定的字符,这样常量就有了统一的表现形式,不会出现输入错误导致的不一致性。另外宏常量意义明确,大大改善了代码的可读性。 只读的变量也可以实现上述宏常量所带来的可移植性、可靠性及可读性等特点,但其要占据存储空间,需要访问内存,相比宏常量的立即数寻址而言效率要低。在C中提倡用const只读变量来定义常量,是因为这样可以提供更严格的类型安全检查。但由于C中const只读变量不能用于某些场合,因此在嵌入式C中仍多数采用宏来定义常量。 1.2 宏定义的基本规则下面以一个实例来说明宏定义的基本规则,如用预处理指令#define 声明一个常量,用以表明1年中有多少秒,不考虑润年#define C_SECONDS_PER_YEAR (60 * 60 * 24 * 365)ULa) 命名风格,为了与普通变量区分开来,宏定义通常全部大写,多个单元之间用下划线隔开;b) 整个表达式应括起来,若有参数则应将每个参数都括起来,防止替换扩展后可能带来的异常问题;c) 常量表达式先合并后再替换。预处理器将为你计算常量表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有运行性能代价的。d) 为常量添加类型信息。宏的不足之一在于缺乏类型安全检查,人为的提供类型信息可以有效检查出此类问题。UL告诉编译器这个常量是无符号长整型数,因此将其赋值给u16型变量会出现告警。 1.3 依赖关系定义宏改善移植性嵌入式系统程序的最大特点是硬件平台的多变性,因此需要根据具体的应用情况更改大量配置,而这些配置基本都是由宏定义来实现的,放在特定的头文件中,与其他的代码隔离,在一定程度上改善了代码的可移植性。但有些时候,多个宏定义有严重的依赖关系,增减某个宏会引起其他定义的更改,如何定义这些宏对嵌入式程序的可移植性有很大影响。 A常量分别定义 #define C_DD_MODULE_ID_AOM (0x00010101) /* AOM模块ID */#define C_DD_MODULE_ID_RRCM (0x00010102) /* RRCM模块ID */#define C_DD_MODULE_ID_RLC (0x00010103) /* RLC模块ID */#define C_DD_MODULE_ID_TRM (0x00010104) /* TRM模块ID */#define C_DD_MODULE_ID_MCP_MIN (C_DD_MODULE_ID_AOM) #define C_DD_MODULE_ID_MCP_MAX (C_DD_MODULE_ID_TRM) B依赖定义 #define C_DD_MODULE_ID_MCP_MIN (0x00010101) /* MCP最小模块ID */#defineC_DD_MODULE_ID_AOM (C_DD_MODULE_ID_MCP_MIN) /* AOM模块ID */#define C_DD_MODULE_ID_RRCM (C_DD_MODULE_ID_AOM + 1) /* RRCM模块ID */#define C_DD_MODULE_ID_RLC (C_DD_MODULE_ID_RRCM + 1) /* RLC模块ID */#define C_DD_MODULE_ID_TRM (C_DD_MODULE_ID_RLC + 1) /* TRM模块ID */#define C_DD_MODULE_ID_MCP_MAX (C_DD_MODULE_ID_TRM) /* MCP最大模块ID */ “A常量分别定义”方式,因为各个宏定义值必须连续,若更改或者删除C_DD_MODULE_ID_AOM,其他的定义基本都受到影响,将严重影响到代码的可扩充性和可裁减性。 “B依赖定义”方式,其原则是:a) base用常量定义;b) 第一个定义为base;c) 其他的在上一个基础上加1; d) max项即为最后一项。这样整体改动起来只需要更改base;在中间删除或添加部分项时只需要更改一个上下衔接处即可;添加则比较简单,只需要在原有最后项后添加即可。这种方式若改动部分定义对其他定义的影响最小,大大改善了代码的可移植性。 1.4 通过偏移量和掩码进行位操作嵌入式系统经常需要和硬件打交道,而配置硬件寄存器则是系统初始化阶段的重要任务,如何清晰明了的进行配置决定了代码的可读性。尽管可以使用位域,但位域是不可移植的,因此利用宏定义来解决可移植性问题。 对于每一个待操作相应位来说,应具备以下几个标识:待操作的位名称B_NAME;操作位所占据的位宽B_WIDTH_NAME操作位第一位的偏移量B_SHIFT_NAME操作位的掩码B_MASK_NAME 以PRI为例进行说明:#define PRI DD_C64_EDMA_OPT_PRI#define C_WIDTH _DD_C64_EDMA_OPT_PRI (3)#define C_SHIFT_DD_C64_EDMA_OPT_PRI (29) 可以手动定义对应位的掩码,如下:#define C_MASK_DD_C64_EDMA_OPT_PRI (0xe0000000)但更好的方式是利用位宽和偏移量来自动构成掩码#define BIT_MASK(_name) (1U C_WIDTH _#_name)-1)( C_SHIFT_#_name)#define C_MASK_DD_C64_EDMA_OPT_PRI BIT_MASK(PRI)BIT_MASK(PRI)经过宏替换后即为:(1U( C_WIDTH _DD_C64_EDMA_OPT_PRI)-1) ( C_SHIFT_DD_C64_EDMA_OPT_PRI) 对于每个位的取值也应该用宏定义来表示,这样清晰明确#define C_DD_C64_EDMA_OPT_URGENT_PRI (0x0)#define C_DD_C64_EDMA_OPT_HIGH_PRI (0x1)#define C_DD_C64_EDMA_OPT_MEDIUM_PRI (0x2)#define C_DD_C64_EDMA_OPT_LOW_PRI (0x3) 具备了掩码和偏移量即可对各个位进行操作了#define SET_BITS(_reg,_name_val)(_reg)=(_ reg)&(BIT_MASK(_name) | (_val)( C_SHIFT_#_ name)&(BIT_MASK(_name) 通过如下方式调用设置优先级SET_BITS(u32Opt, PRI, C_DD_C64_EDMA_OPT_HIGH_PRI);即实现了将u32Opt的PRI等位设置为C_DD_C64_EDMA_OPT_HIGH_PRI SET_BITS宏可应用于待操作的位为多位的情况,当待操作的位仅为一位时,可用更简单的操作方式#define SET_BIT(_reg,_name) (_reg) |= (BIT_MASK(_name)#define CLR_BIT(_reg,_name) (_reg) &= (BIT_MASK(_name) 以TCINT为例:#define TCINT DD_C64_EDMA_OPT_TCINT#define C_WIDTH _DD_C64_EDMA_OPT_TCINT (1)#define C_SHIFT_DD_C64_EDMA_OPT_PRI (20)SET_BIT(u32Opt, TCINT)CLR_BIT(u32Opt, TCINT) 本文来自CSDN博客,转载请标明出处:/sailor_8318/archive/2008/07/16/2663254.aspx嵌入式系统程序可移植性设计及性能优化之二数据结构设计 Sailor_forever sailing_9806163.com 转载请注明/sailor_8318/archive/2008/07/17/2663633.aspx 【摘要】本章介绍了结构体中成员的对齐规则,及在此规则上如何调整成员顺序或填充部分字段保证其所占内存大小不会因为编译器的不同导致差异。然后介绍了如何利用位域设计网络通信协议及由此带来的大小端系统的可移植性问题;同时介绍了用位域在特定平台上配置硬件寄存器的技巧。最后介绍了如何利用union在不同系统间传输变长数据包及如何进行数据封装并提供相关操作接口的相关技巧。 【关键词】嵌入式,可移植性,数据结构,结构体对齐规则,非对齐访问,位域,传输协议,大小端,硬件配置字,数据封装,初始化操作接口 2 数据结构设计. - 4 -2.1 结构体中成员对齐规则. - 4 -2.1.1 自然对界. - 4 -2.1.2 指定对界. - 4 -2.2 合理设计成员顺序. - 5 -2.2.1 减少结构体存储空间. - 5 -2.2.2 填充部分域,避免字节对齐问题. - 6 -2.2.3 字节对齐问题实例. - 7 -2.3 采用位域构造结构体. - 8 -2.3.1 位域设计传输协议. - 8 -2.3.2 位域的可移植性问题. - 9 -2.3.3 位域设计硬件配置字. - 10 -2.4 通过union和struct传递不同格式报文. - 11 -2.5 将相关功能变量封装为结构体. - 13 - 1 数据结构设计程序设计是算法和数据结构的集合,因此数据结构是程序设计的基础,就象建造豪华的公寓也必须从一砖一瓦开始。大型的C/C+程序,势必要涉及一些进行数据组合的结构体,这些结构体可以将原本意义属于一个整体的数据组合在一起。嵌入式系统软硬件平台具备多变性,不同处理器对于数据对齐访问的要求不同,另外不同的编译器可以设置不同的数据对齐规则,这些都将导致结构体在不同软硬件平台下的可移植性问题。 在网络协议、通信控制等嵌入式系统的C/C+编程中,经常要传送的不是简单的字节流(u8型数组),而是多种数据组合起来的一个整体,其表现形式是一个结构体。经验不足的开发人员往往将所有需要传送的内容依顺序保存在u8型数组中,通过指针偏移的方法传送网络报文等信息。这样做编程复杂,易出错,按顺序存储的数组不便于增添其他成分,因此一旦控制方式及通信协议有所变化,程序就要进行非常细致的修改,移植性差;而结构体的成员增减时不影响原有单元的操作,因为编译器会自动计算各个成员的偏移量。 因此从某种程度上来说,会不会用struct及怎样用struct对程序的可移植性和可读性有较大影响。 1.1 结构体中成员对齐规则1.1.1 自然对界对于结构体,编译器会自动进行成员变量的对齐,以提高运算效率。缺省情况下,编译器为结构体的每个成员按其自然对界(natural alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。自然对界即默认对齐方式,是指按结构体的成员中size最大的成员对齐。例如:struct naturalalign u8 u8a; u16 u16b; u8 u8c; 在上述结构体中,size最大的是u16,其长度为2字节,因而结构体中的u8成员a、c都以2为单位对齐,sizeof(naturalalign)的结果等于6。1.1.2 指定对界一般地,可以通过下面的方法来改变缺省的对界条件:a) 使用伪指令#pragma pack (n),编译器将按照n个字节对齐;b) 使用伪指令#pragma pack (),取消自定义字节对齐方式。所有处于“#pragma pack (n)”和“#pragma pack ()”之间的结构体将按照指定对界对齐。当pragma pack (n)中指定的n大于结构体中最大成员的size,则其不起作用,结构体仍然按照size最大的成员进行对界。例如:#pragma pack (n)struct pack u8 u8a; u32 u32b; u8 u8c;#pragma pack () 当n为4、8、16时,其对齐方式均一样,sizeof(naturalalign)的结果都等于12。而当n为2时,其发挥了作用,使得sizeof(naturalalign)的结果为8。 另外,通过_attribute(packed (n)也可以单个结构体的成员对齐在n字节边界,这样即使平台改变了,编译器不同了,也将采用统一的对界方式,这种方式对于不同体系的处理器之间的数据交互很重要,移植性好。 1.2 合理设计成员顺序1.2.1 减少结构体存储空间在默认的自然对界情况下,若最大数据类型为u32,则u32四字节对齐,u16二字节对齐,整个结构体大小为sizeof(u32)的倍数,该结构体定义的变量首地址自动对齐在sizeof(u32)边界上。故: struct naturalalignA u16 u16a; u32 u32b; u8 u8c; struct naturalalignB u16 u16a; u8 u8c; u32 u32b; struct naturalalignC u8 u8c; u16 u16a; u32 u32b; sizeof(naturalalignA) = 12sizeof(naturalalignB) = 8sizeof(naturalalignC) = 8 struct naturalalignD u8 u8a; u16 u16b; u8 u8c; struct naturalalignE u8 u8a; u8 u8c; u16 u16b; sizeof(naturalalignD) = 6sizeof(naturalalignE) = 4 struct naturalalignF u8 u8a; u32 u32b; u8 u8c; struct naturalalignG u8 u8a; u8 u8c; u32 u32b; sizeof(naturalalignF) =12sizeof(naturalalignG) = 8从上面可以看出,从存储空间的角度看,naturalalignA、naturalalignD、naturalalignF都是不合理的设计。 1.2.2 填充部分域,避免字节对齐问题 struct naturalalignD u8 u8a; u16 u16b; u8 u8c; struct naturalalignH u8 u8a; u8 padding; u16 u16b; u8 u8c; u8 padding; struct naturalalignI u8 u8a; u8 u8c; u16 u16b; 在自然对界情况下,sizeof(naturalalignD) = sizeof(naturalalignH) = 6此时并不会因为填充部分域后导致结构体变大,只是避免编译器自动填充而已。但对于指定对界时可能会使结构体变大。naturalalignI调整了成员的顺序,减少存储空间的同时保证了u16 u16b的对齐,无需设计填充域,同时编译器也不会自动填充 struct naturalalignJ u16 u16a; u8 u8c; u8 padding; u32 u32b; struct naturalalignK u8 u8c; u8 padding; u16 u16a; u32 u32b; struct naturalalignL u8 u8c; u16 u16a; u8 padding; u32 u32b; naturalalignJ中填充后保证了u32 u32b的对齐,naturalalignK填充后保证了u16 u16a的对齐也保证了u32 u32b的对齐,要注意的是naturalalignL表面上填充域后u32 u32b对齐了,但由于u16 u16a未处于二字节对齐边界上,实际上编译器在u8 u8c后自动填充了一个域保证u16 u16a的对齐,在u8 padding后自动填充了三个u8保证u32 u32b的对齐。naturalalignJ和naturalalignK都是合理的填充方式。 #pragma pack (2)struct packA u16 u16a; u32 u32b; u8 u8c;#pragma pack () #pragma pack (2)struct packB u16 u16a; u8 u8c; u32 u32b;#pragma pack () #pragma pack (1)struct packC u8 u8a; u16 u16b; u8 u8c;#pragma pack () 在指定对界情况下,大于pack字节的将按照设定值进行对齐sizeof(packA) = 8sizeof(packB) = 8sizeof(packC) = 4由于packA类型变量对齐在sizeof(u32)边界上,2字节对齐时u32 u32b的地址没有对齐在四字节边界上,此时的影响为:不能进行非对齐访问的处理器:u32 u32temp packA.b将导致处理器内存访问异常;可非对齐访问的处理器:u32 u32temp packA.b对于b的访问实际上是分两个u16来分别访问然后合成一个u32后赋值给u32temp的,比对齐的u32变量访问效率要低。u32 *u32temp &packA.b,因为u32temp为u32型指针变量,其值必须为4的倍数,而(&packA.b)并不是4的倍数,显然此处的赋值是不合理的。指针类型强制转换时也可能存在这种异常问题。 为了避免指定对界不统一带来的内存访问异常问题,在数据结构设计时总的原则是:不考虑编译器自动填充的情况下,通过适当填充使u16对齐在二字节上,u32对齐在四字节上,此时无论编译器何种对界,结构体的大小总是固定的,且不会存在内存访问问题。 struct naturalalignE u8 u8a; u8 u8c; u16 u16b; struct naturalalignK u8 u8c; u8 u8padding; u16 u16a; u32 u32b; struct naturalalignH u8 u8a; u8 u8padding; u16 u16b; u8 u8c; u8 u8padding; 1.2.3 字节对齐问题实例以我在NTT DoCoMo实习期间遇到的一个实例来说明对齐方式不同导致的不同处理器间的数据交互问题。 三种平台:a) ARM Linux,嵌入式平台,未定义数据结构,转发字节流,采用偏移量;b) Windows Mobile PDA,嵌入式平台,将数据组合为了结构体,按照字节对齐;c) Windows XP PC,自然对界。 相应的数据结构定义如下:typedef struct _DBGEstEntry u16 id; u8 hopcount; u8 sendEst; DBGEstEntry; /add by oy 06.8.4typedef struct _DebugPacket u8 estEntries; DBGEstEntry estList; DebugPacket; ARM和PDA交互时因为都是按照字节对齐的,在将字节流强制转换为结构体时,对数据的解析方式一致,没有任何问题。后将代码移植到PC平台,同样的程序结果却不一样。究其原因就是因为不同平台采用了不一致的对齐方式。 PC平台下VC默认采用8字节自然对界,由于DBGEstEntry最大类型为uu3216_t,因此DebugPacket的成员estEntries后默认补齐了一个u8,相当于此时不同平台采用了不一样的结构来解析数据,就出现异常了。 添加一个填充域,指针强制转换时,地址前移一个以取消填充域的影响。typedef struct _DebugPacket u8 reserved; u8 estEntries; DBGEstEntry estList; DebugPacket; 或者针对此数据结构采用指定的对齐方式,和ARM和PDA平台一致。typedef struct _DebugPacket u8 reserved; u8 estEntries; DBGEstEntry estList; _attribute(packed (1) DebugPacket; 因此对于嵌入式平台上的数据结构设计,一定要合理调整顺序及填充部分域避免平台和编译器的不同导致的字节对齐问题。 1.3 采用位域构造结构体1.3.1 位域设计传输协议在大多数情况下,我们一般这样定义结构体:/* 与MCP驱动通信交互的数据帧头部标识*/typedef struct tag_STRU_DD_FRMHDR u8 u8FrmFlag; /* 帧头标识 */u8 u8SrcModuleId; /* 源模块ID */u8 u8DstModuleId; /* 目的模块ID */u8 u8padding;u16 u16Length; /* 数据长度 */u16 u16padding STRU_DD_FRMHDR; 对于一般的应用,这已经能很充分地实现数据的“封装”。但是在实际工程中,由于传输链路中每次传输的数据有限,头部越长,导致有效数据越少,如CAN总线通信中,数据总长8个字节,有效的减少头部信息就很重要。由于数据长度u16Length不便缩短,而u8SrcModuleId和u8DstModuleId分别用四位就可表示,因此可以用位域来表示此结构体。 位域就是一个基本类型变量中的不同的位表示不同的含义。譬如一个硬件寄存器,假设为16 bit ,而每个bit 都可以表达不同的含义。这个时候我们用什么数据结构来表达这个寄存器呢?答案还是结构体!这时要用到结构体的高级特性,就是在基本成员变量的后面添加“: 数据位数”组成新的结构体,如下:typedef struct tag_STRU_DD_FRMHDRu32 bit8FrmFlag :8; /* 帧头标识 */u32 bit4SrcModuleId:4; /* 源模块ID */u32 bit4DstModuleId :4; /* 目的模块ID */u32 bit16Length:16; /* 数据长度 */ STRU_DD_FRMHDR; 上述结构体中的四个成员加起来只占用了一个unsigned u32 的空间。基本成员变量被拆分后,访问的方法仍然和访问没有拆分的情况是一样的。 1.3.2 位域的可移植性问题在拆分基本成员变量的情况下,我们要特别注意数据的存放顺序,这还与CPU 是Big endian 还是Little endian 来决定。Little endian 和Big endian 是CPU 存放数据的两种不同顺序。对于整型、长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节);而Little endian 则相反,它认为第一个字节是最低位字节(按照从低地址到高地址的顺序存放数据的低位字节到高位字节)。 如我们定义IP 包头结构体为:struct iphdr #if defined(_LITTLE_ENDIAN_BITFIELD) u8 ihl:4, version:4; #elif defined (_BIG_ENDIAN_BITFIELD) u8 version:4, ihl:4; #else #error Please fix #endif u8 tos; u16 tot_len; u16 id; u16 frag_off; u8 ttl; u8 protocol; u16 check; _u32 saddr; _u32 daddr; ; 在Little endian 模式下,iphdr 中定义:u8 ihl:4, version:4; 因为位域是从低位字节开始计算的,其存放方式为:第1 字节低4 位 ihl ,第1 字节高4 位 version (IP 的版本号)若在Big endian 模式下还这样定义,则存放方式为:第1 字节低4 位 version (IP 的版本号),第1 字节高4 位 ihl 这与实际的IP 协议是不匹配的,所以在Linux 内核源代码中,IP 包头结构体的定义利用了宏来区分两种不同的情况。#if defined(_LITTLE_ENDIAN_BITFIELD) #elif defined (_BIG_ENDIAN_BITFIELD) #endif 对于咱们的应用情况,此STRU_DD_FRMHDR是PowerPC和DSP交互时使用的,目前二者都为big endian模式,因此二者采用位域对数据解析时是一致的,但若一方为小端,则数据解析将出错。 由此我们总结位域的使用要点:a) C/C+ 语言的结构体支持对其中的基本成员变量按位拆分,其使用方法和结构体一致,便于编程;b) 但要特别注意拆分后的数据的存放顺序,为了支持代码的跨平台移植,应用宏定义来区分大小端的不同数据结构。 1.3.3 位域设计硬件配置字在嵌入式系统中经常要和底层硬件打交道,此时需要配置各种硬件选项,而这些选项通常都是由一个寄存器的不同位表示的,进行配置时经常要用到与或、移位等操作,编程不便,因此可以利用位域的形式来访问不同域,其和结构体的访问形式一样,非常方便。/* struct defined for the OPTION word for EDMA - big endian */typedef struct tag_STRU_DD_C64_EDMA_OPT u32 u32bit3Pri : 3; /* Priority */ u32 u32bit2Esize : 2; /* Element size */ u32 u32bit1TwoDs : 1; /* Source dimension */ u32 u32bit2Sum : 2; /* Source address update mode */ u32 u32bit1TwoDd : 1; /* Destination dimension */ u32 u32bit2Dum : 2; /* Destination address update mode */ u32 u32bit1Tcu32 : 1; /* Transfer complete u32errupt */ u32 u32bit4Tcc : 4; /* Transfer complete code */ u32 u32bit1Rsvd1 : 1; /* Resverd */ u32 u32bit2Tccm : 2; /* Transfer complete code */ u32 u32bit1Atcu32 : 1; /* Alternate transfer complete u32r */ u32 u32bit1Rsvd2 : 1; /* Resverd */ u32 u32bit6Atcc : 6; /* Alternate transfer complete code */ u32 u32bit1Rsvd3 : 1; /* Resverd */ u32 u32bit1Pdts : 1; /* PDT mode for source */ u32 u32bit1Pdtd : 1; /* PDT mode for Destination */ u32 u32bit1Link : 1; /* Link */ u32 u32bit1Fs : 1; /* Frame synchronization */ STRU_DD_C64_EDMA_OPT; 硬件寄存器通常上电后各位为0,大多数选项都是默认的,只需配置部分非0的选项。采用位域时只会更改相关的配置项,不会影响其他位。而没有位域时需要与或等操作避免影响其他位。 对于硬件配置字通常定义相关常量来表示不同的配置,如下:/* Define constants to construct EDMA option word */* Priority, 3bit */#define C_DD_C64_EDMA_OPT_URGENT_PRI (0x0)#define C_DD_C64_EDMA_OPT_HIGH_PRI (0x1)#define C_DD_C64_EDMA_OPT_MEDIUM_PRI (0x2)#define C_DD_C64_EDMA_OPT_LOW_PRI (0x3) /* Element size, 2bit */#define C_DD_C64_EDMA_OPT_ESIZE_32 (0x0)#define C_DD_C64_EDMA_OPT_ESIZE_16 (0x1)#define C_DD_C64_EDMA_OPT_ESIZE_8 (0x2) 1.4 通过union和struct传递不同格式报文网络通信中进行数据包交互时通常以固定数据区传递,但每次传递的消息类型可能不同,因此固定数据区的有效数据长度可能不一样,此时需要字段标识消息类型和消息长度,以便双方对数据进行解析。 每种消息都有共有的消息头开始,然后是特定的消息信息,这样消息的结构将变得非常清晰,统一的格式如下:typedef struct tag_STRU_MAT_XXX STRU_DD_MSG_HDR struMsgHdr; STRU_DD_XXX struXXX; STRU_MAT_XXX; 消息头如下:typedef struct tag_STRU_DD_MSG_HDR u8 u8OpCode; u8 u8Len; u8 au8MsgHdrDataC_DD_COMM_MSG_HEADER_DATA_BYTE_LEN; STRU_DD_MSG_HDR;通过消息头中的u8OpCode操作码来确定消息类型,也就确定了消息的具体内容;若对于某种消息,其有效数据长度是可变的,则u8Len将标识消息数据域的长度 当消息内容固定时,最好以结构体封装消息内容。typedef struct tag_STRU_MAT_SET_BPP_TOD_SFN_TSN_REQ STRU_DD_MSG_HDR struMsgHdr; u32 u32TodPart1; u32 u32TodPart2; u16 u16SfnPeriod; u16 u16TsnPeriod; u16 u16Sfn; u16 u16Tsn; STRU_MAT_SET_BPP_TOD_SFN_TSN_REQ;上述方式消息内容零散,同时也不便于将其另行传递给其他模块。 封装后的结构如下:typedef struct tag_STRU _BPP_TOD_SFN_TSN_PARAM u32 u32TodPart1; u32 u32TodPart2; u16 u16SfnPeriod; u16 u16TsnPeriod; u16 u16Sfn; u16 u16Tsn; STRU _BPP_TOD_SFN_TSN_PARAM; typedef struct tag_STRU_MAT_SET_BPP_TOD_SFN_TSN_PARAM _REQ STRU_DD_MSG_HDR struMsgHdr; STRU _BPP_TOD_SFN_TSN_ PARAM struTimeParam; STRU_MAT_SET_BPP_TOD_SFN_TSN_PARAM _REQ; 不同消息STRU_MAT_XXX长度不同,但又需要统一的数据区来存储,因此需要定义一个数据结构来统一各种消息,关键在于统一的数据区长度如何确定,其既保证可以容纳所有消息类型同时又不浪费存储空间? 一种方式算出各种消息占用的最大存储空间,对于具体的消息数据采用纯数组存储,其根据头部的u8OpCode确定消息类型,然后再强制转换消息数据进行解析。t
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 风险控制矩阵分析
- 电大电工考试题及答案
- 农产品供应链合作协议内容
- 外科护理学考试题库及答案中专
- 大堂转岗考试题及答案
- 绿色采购和低碳生产承诺书4篇
- 学习中的挫折与坚持议论文9篇
- 《世界地理概况:高中地理课程教案》
- 客户服务支持响应及反馈跟踪系统
- 医疗垃圾处理规范课件
- 2025-2026学年冀人版三年级科学上册(全册)教学设计(附目录)
- 磷化铝管理办法
- 手术室专科护士职业考试试卷与答案
- 门窗工程管理办法
- 小学体育家长会课件
- 依法治校视角下高校后勤管理法律风险的识别与化解策略
- 2025年法学专业基础课程试题及答案
- 腰椎管狭窄症病例讨论
- 部编版语文(2024)二年级上册第一单元综合素养测评A卷(含答案)
- 工程质量事故案例课件
- 多囊卵巢综合症及护理方法
评论
0/150
提交评论