add00 发表于 2012-8-1 13:19:06

转贴一个 结构体、联合体的应用,以及字节对齐和字节序...

希望对需要的人有用,自己收藏~~

结构体、联合体的应用,以及字节对齐和字节序的问题

通讯中,用过的非常多。给你一个我的例子

typedef union
{
    FLOAT32      fVal;
    INT32      dig;
    INT32      iVal;
    struct{
      FLOAT32 x;
      FLOAT32 y;
    }complex;
    FLOAT64   dfVal;
    PROT_TIME   time;
}PROTEVENT_VALTYPE;    //不同类型的数值

typedef struct
{
    struct
    {
      UINT16    paraType;
      UINT8    valType;
      UINT8   widthVal;
      PROTEVENT_VALTYPE val;
      UINT16    paraGroup;
      UINT8   phs;
      UINT8   lenName;
    }head;
    UINT8    name;
}PROTMSG_EVENT_PAR;


对于那种一个整数和几个字节取值的问题,建议不要用结构联合来实现。如:

union bits32
{
    int num;
    struct
    {
      char c1;
      char c2;
      char c3;
      char c4;
    }byte;
};


这个在不同的CPU架构变现不相同,就是CPU的高低次序问题。在普通的PC即x86cpu上,是小头在前,即c1对应的num的第一个字节,但是在其它一些如PowerPC、sun的SPARC架构CPU上,是大头在前,c1就对应num的第4个字节。
在网络传输中,对这个问题很敏感,就是发生的字节次序问题。在TCP/IP中,规定是网络次序,具体参考一下TCP/IP的数据。里面有不少网络次序数据和本机数据的转换问题。
为了避免这种问题,我们一般在通信中,采用的是移位操作。如

/*****整数和单字节数转换操作,通过移位避开次序问题*****/
#define BYTE0(intval) ( (UINT8)(0x000000ff&(intval)) )
#define BYTE1(intval) ( (UINT8)(( 0x0000ff00&(intval))>>8) )
#define BYTE2(intval) ( (UINT8)(( 0x00ff0000&(intval))>>16) )
#define BYTE3(intval) ( (UINT8)((0x0ff000000&(intval))>>24) )

/*******************字节组合定义*******************/
#define UINT16COMB(b1,b0)    ( (UINT16)(b0) | (((UINT16)(b1))<<8) )
#define INT16COMB(b1,b0)    UINT16COMB(b1,b0)

#define UINT32COMB(b3,b2,b1,b0)            /
                (   (UINT32)(b0)    /
                | (((UINT32)(b1))<<8)    /
                | (((UINT32)(b2))<<16)    /
                | (((UINT32)(b3))<<24) )
#define INT32COMB(b3,b2,b1,b0)    UINT32COMB(b3,b2,b1,b0)

使用时,可以用:

c1=BYTE0(num);
c2=BYTE1(num);
...
num=UINT32COMB(c3,c2,c1,c0);

实际上移位操作,对于CPU来说,基本上是一个指令周期,比你直接用struct和union还要快。这个问题涉及到32位CPU的整字对齐和整字操作处理问题和CPU的指令优化,具体可以去参考CPU指令的书籍。
对齐规则由编译选项决定的,一般编译器采用缺省的编译选项。一般存储单元按照CPU的字长对齐,对于目前32位主流系统,基本的数据类型char、short、int、float,对齐在整字的开始。
如struct
{
   char c;
   int i;
   float f;
};
c占用第一个字长的第一个字节,而后面的3个字节变长存储空洞;i和f各占1个字长。
struct
{
   char c;
   char c1;
   int i;
   float f;
};
这种情况下,c1将分配在c之后,占一个字节,而c1后面就留出来2各空洞。
所以在组织struct或者class时,注意一下成员分布的合理,综合一下存储分配情况。但是从CPU的指令操作上看,CPU一般按照一个字长来执行,操作一个int数要比一个char效率高。也就说说,当CPU读取一个char数时,CPU先从内存中读取一整个字长值到寄存器中,然后将相应char所在的那个字节提取出来,从而完成一个char的取值。
另外:编程时千万注意float *pFVal;指针的使用,浮点数指针一定要指向一个整字起始的内存位置,如上面的&c1地址,否则在一些特定的CPU或单片机中,对非对齐的浮点指针操作,会发生崩溃问题,这个和浮点指令的兼容性问题。典型的是在sun的sparc、POWERPC的一些cpu上就会发生崩溃问题。



想改变编译器的对齐规则,可以在代码中加入:

#pragma pack(push, 1)

.....//代码

#pragma pack(pop)

自:blog.csdn.net/ljhnew/article/details/5829821

avrstm32 发表于 2012-8-1 13:24:00

谢谢,标记一下,等会儿再看。

dory_m 发表于 2012-8-1 13:32:30

学习,在学习!!!

raxb 发表于 2012-8-1 14:54:58

Mark一下...
页: [1]
查看完整版本: 转贴一个 结构体、联合体的应用,以及字节对齐和字节序...