现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

位域及,字节序其注意事项

2012-07-31 06:32 工业·编程 ⁄ 共 2143字 ⁄ 字号 暂无评论

1)对于位域结构中的变量来说,其长度不能跨越字节,也就是说不能超过8位。当然如果设置空白位(无名变量,仅仅用作占位的)是没有这个限制的。如果一个字节剩下的位长度不够一个位域,那么从下个字节开始,也可有意置某个位域从下个字节开始。例如:

struct bits4_5
{  //一个从到小的存放顺序结构体
   unsigned : 10;  //从位15向下跳到位5
   unsigned  bit5:1;
   unsigned bit4:1;
};
例二:
struct xx
{
   unsigned a:4;
   unsigned :2;
   unsigned b:4; // 从第二个字节开始
};
 
(2)不同的编译器结构存储的方式不一样相同,这个同不同的机器内存中存放变量的字节序不同一个道理。我们知道,关于字节序有大端和小端之分。一般来说,Intel处理器使用的是小端(little endian),Moto处理器使用的是大端(记忆中好像就Intel的用小端,其它的基本上都是大端)。小端和大端的区别在于,内存对于变量的存放规则不同。对于小端来说:低位字节存放在内存中相对低地址;高位字节存放在内存中相对高地址。示例如下:一个WORD32内容的变量,占4个字节:Byte3 Byte2 Byte1 Byte0,在内容中存放:
      Base Address +0      Byte0
Base Address +1      Byte1
Base Address +2      Byte2
Base Address +3      Byte3
        类推,大端存放恰恰相反。这个主要在网络处理中使用的比较多。因为客户端因为受到不同的处理器限制,因为要实现不同机器间数据的传递正确性,要同一规则。我们在网络中使用的是网络字节序,也就是大端,所以网络上发送字节序要注意,特别是建立socket时目的方的IP地址和Port的表示要进行处理才行。可能有人会问及这里为什么名说到字节序却没有提及传输的数据。因为我们大部分都是使用字节流byte stream的TCP方式,所以不存在字节序问题。
            上面说的是字节序。除此之外,不同的编译器存储结构(类)的方式也是不一样的,有的是采用“从小到大的字节存储顺序”,有的是采用“从大到小的字节存储顺序”。例如下面的结构定义:
             
struct bits4_5   // 按照从小到大字节存储顺序
       {
           unsigned :4; // 跳过位0—位3
           unsigned bit4:1;
           unsigned bit5:1;
};
struct bits4_5 // 按照从大到小字节存储顺序
{
   unsigned:10;  // 从位15跳过10位至为6
   unsigned bit5:1;
   unsigned bit4:1;
} 
下面看一个简单的例子,主要是调试前后台程序的时候发现的问题。当时的环境为:前台是跑在单板上的程序,其中单板上运行的是VxWorks实时操作系统;后台的程序是运行在PC机器上,前台单板通过网口和后台连在一个Hub上实现互通。
在后台有结构如下(为了不引起麻烦,修改了其中的变量名称)typedef struct NetAddr
{
   DWORD a:2;
   DWORD b:2;
   DWORD c:3;
   DWORD d:1;
   DWORD e:4;
   DWORD f:4;
   DWORD g:4;
   DWORD h:4;
   DWORD i:8;
}T_NetAddr;
typedef union VNetAddr
{  // 针对不同的平台使用的地址不同
   T_NetAddr tNetAddr; 
   DWORD dwAddr;
}T_VNetAddr;
在后台中传递给前台,由于字节序不一样,要进行转换,这里转换就要求按照字节进行调整了,这个这里就不说了,这里我们只是看看结构体中位域的存放规则。这里我们的PC机器是按照小端进行存放的。
在main里面我们如下调用:
T_VNetAddr net;
   net.tNetAddr.a=1;
   net.tNetAddr.b=0;
   net.tNetAddr.c=0;
   net.tNetAddr.d=0;
   net.tNetAddr.e=2;
   net.tNetAddr.f=9;
   net.tNetAddr.g=0;
   net.tNetAddr.h=0;
   net.tNetAddr.i=128;
我们可以观察内存中的net变量的值,各个位域的值如上面的赋值所示,存放的时候按照结构体中定义的顺序一个挨着一个顺序存放(按照从小到大的地址存放顺序,最前面定义的位域存放在低地址,后面定义的位域存放在高地址端):
             b7 b6 b5  b4 b3 b2  b1 b0
第一个字节: 0  0  0  0  0  0  0  1         b1b0=01 对应于位域a
第二个字节   1  0  0  1  0  0  1  0    b7b6b5b4=9 对应于位域f  b3b2b1b0=2对应e
第三个字节   0  0  0  0  0  0  0  0
第四个字节   1  0  0  0  0  0  0  0  b7b6b5b4b3b2b1b0=128对应于i=128
这样看就比较清晰了,如果我们查看一下net.dwAddr就会发现其值为0x80009201,为什么呐?
结构体存放内部位域的顺序是按照小端,前面定义的位域存放在低地址,这样依次从前到后存放的地址是由低向高的存放。读取DWORD类型的变量的时候,按照小端,地位字节存放在低地址,高位字节存放在高地址的规则,DWORD类型的dwAddr的字节排列如下:
第四个字节    第三个字节    第二个字节   第一个字节
80              00            92            01
没有问题!!! 
注意:千万不要误以为是:01920080(从前往后读)。

给我留言

留言无头像?