字节序转换与结构体位域(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;
时间: 2024-10-13 01:45:34

字节序转换与结构体位域(bit field)值的读取的相关文章

字节序转换与结构体位域(bit field)值的读取 Part 2 - 深入理解字节序和结构体位域存储方式

上一篇文章讲解了带位域的结构体,在从大端机(Big Endian)传输到小端机(Little Endian)后如何解析位域值.下面继续深入详解字节序,以及位域存储的方式. (1) 我们知道,存储数字时,对小端机而言,数字的低位,存在低地址,高位存在高地址.大端机正相反. (2) 读取的方式,也是一样的.对于小端机,读出的低地址位作为数字的低位. (3) 此外Big-Endian/Little-Endian存储顺序,不仅仅针对字节,还针对字节内的比特位.对于小端机而言,字节内的8个比特,低地址端比

数组强制转换成结构体指针,结构体内部指针的指向问题

如果直接操作结构体成员是不会取到不期望的值 但是对于要求连续数据格式的时候需要考虑对齐的问题 例如通讯中的数据帧格式等 ,如 ip数据包等#pragma   pack(1) struct   tagStruct {     ... } t; #pragma   pack() 的方式来强制连续存放 其中前面   pack(1)   是指对齐边界为   1 1.几个结构体例子: struct{short a1;short a2;short a3;}A; struct{long a1;short a2

字节序转换以及判断字节序

在网络信息跨主机传输过程中,不同主机的字节序问题可能不同,因此必须进行字节序的转换. 本地字节序--> 网络字节序 -->本地字节序 字节序转换函数: htons和htonl是将本地字节序转换为网络字节序,htons是对16位整数进行转换,htonl是对32位正数进行转换,ntohs和ntohl恰好相反. 判断主机字节序和网络字节序: #include<arpa/inet.h> #include<stdio.h> //judge host endian void jud

网络通信之 字节序转换原理与网络字节序、大端和小端模式

原文地址:http://www.cnblogs.com/fuchongjundream/p/3914770.html 一.在进行网络通信时是否需要进行字节序转换? 相同字节序的平台在进行网络通信时可以不进行字节序转换,但是跨平台进行网络数据通信时必须进行字节序转换. 原因如下:网络协议规定接收到得第一个字节是高字节,存放到低地址,所以发送时会首先去低地址取数据的高字节.小端模式的多字节数据在存放时,低地址存放的是低字节,而被发送方网络协议函数发送时会首先去低地址取数据(想要取高字节,真正取得是低

网络通信时字节序转换原理与网络字节序、大端和小端模式

引言:在进行网络通信时是否需要进行字节序转换? 相同字节序的平台在进行网络通信时可以不进行字节序转换,但是跨平台进行网络数据通信时必须进行字节序转换. 原因如下:网络协议规定接收到得第一个字节是高字节,存放到低地址,所以发送时会首先去低地址取数据的高字节.小端模式的多字节数据在存放时,低地址存放的是低字节,而被发送方网络协议函数发送时会首先去低地址取数据(想要取高字节,真正取得是低字节),接收方网络协议函数接收时会将接收到的第一个字节存放到低地址(想要接收高字节,真正接收的是低字节),所以最后双

网络通信之字节序转换原理与网络字节序、大端和小端模式

一.在进行网络通信时是否需要进行字节序转换? 相同字节序的平台在进行网络通信时可以不进行字节序转换,但是跨平台进行网络数据通信时必须进行字节序转换. 原因如下:网络协议规定接收到得第一个字节是高字节,存放到低地址,所以发送时会首先去低地址取数据的高字节.小 端模式的多字节数据在存放时,低地址存放的是低字节,而被发送方网络协议函数发送时会首先去低地址取数据(想要取高字节,真正取得是低字节),接收方网络 协议函数接收时会将接收到的第一个字节存放到低地址(想要接收高字节,真正接收的是低字节),所以最后

关于c语言中的结构体使用偏移量求值问题

最近在看nginx源码,看到定时器的时候,发现一个结构体利用偏移量求值问题, 结构体相信做c开发的都遇到过,那么不知你对结构体中成员变量偏移这块是如何理解的; 首先我们先看一下nginx中的那个让我迷惑的地方 ev =    (event_t*)((char*)node - offsetof(event_t, timer)); 这里,可以得知道是利用event_t结构体的timer变量,来反求event_t结构体的地址 说明一下: event_t是一个结构体 node 也是一个结构体 timer

主机字节序和网络字节序转换

为什么要转换? 主机字节序:整数在内存中保存的顺序,不同的处理器对应不容的模式 Little endian 将低序字节存储在起始地址 Big endian    将高序字节存储在起始地址 网络字节序:整数在网络中的发送顺序 网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型.操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释. 网络字节顺序采用big endian排序方式 htons 本地的无符号short型主机字节序转换为网络字节序 htonl    

C 结构体位域

位域 : 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位.例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可.为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”.所谓“位域”是把一个字节中的二进位划分为几 个不同的区域,并说明每个区域的位数.每个域有一个域名,允许在程序中按域名进行操作. 这样就可以把几个不同的对象用一个字节的二进制位域来表示.位段成员必须声明为int.unsigned int或signed int类型(s