• 字节序转换与结构体位域(bit field)值的读取


    最近又遇到了几年前遇到的问题,标记一下。

    对于跨字节位域(bit field)而言,如果数据传输前后环境的字节序不同(LE->BE,BE->LE),简单地调用(ntohs/ntohl/htons/htonl)并不能正确读取位域的值。

    例如:

    struct _exam_
    {
      unsigned int tag : 6;
      unsigned int field1 : 3;
      unsigned int field2 : 7;
      unsigned int field3 : 11;
      unsigned int pad :  5;
    }Exam;

    其中,tag,field2,pad是字节内位域,field1和field3是跨字节位域。当这个结构体从某个大端序平台(例如MIPS,big-endian)通过网络传送到PC机(little-endian),在pc机上无论调用ntohl与否,直接通过Exam.field3语句都无法获取正确的值。

    解决方案:

    (1)调用ntohl,并保存该变量为一个unsigned int。

    此时Exam的5个成员将暂时按照地址从高到低的顺序排列(正确的情况下,无论BE还是LE,结构体内部的成员都应当按照先后顺序,从低地址到高地址排列)。

     unsigned int temp = 0;
     memcpy(&temp, sizeof(temp), &Exam);
     temp = ntohl(temp);  

    (2)使用位运算符获取位域正确值。

    经过上一步骤,虽然Exam的成员(将temp内的码流当作Exam)在内存中的排列顺序是错的,但我们将错就错。从日常印刷书写的“逻辑视图”角度看,Exam.tag在“最左端”(高位),Exam.pad在“最右端”(低位),且5个位域内的比特顺序也是正确的。因此可以直接用移位运算符获取其中的值。

    struct _exam_ ExamWin32;
    ExamWin32.tag = temp >> 26;   // 高位全部为0,不必使用位与运算
    ExamWin32.field1 = (temp >> 23) & 0x00000007; // 只获取移位操作结果的低3位。
    ExamWin32.field2 =  (temp >> 16) & 0x0000007F; 
    ExamWin32.field3 =  (temp >> 5) & 0x000007FF; 
    ExamWin32.pad = temp & 0x0000001F;
  • 相关阅读:
    面试笔试
    scala(9) Monad
    scala (8) 模糊匹配
    scala (7) Set and Tuple
    scala (6) Map
    scala (5) 可变序列和不可变序列
    scala (4) 可变数组和不可变数组
    scala (3) Function 和 Method
    scala (2) while 和变量
    scala (1) for 循环
  • 原文地址:https://www.cnblogs.com/radiolover/p/5539738.html
Copyright © 2020-2023  润新知