百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

C语言:位域和字节序(c语言位字段)

csdh11 2025-03-18 20:57 1 浏览

1. 粉丝问题

自己编写的一个协议相关代码,位域的值解析和自己想象的有出入。

问题

结构体的头:

解析代码和测试结果:

就是说通过函数hexdump()解析出的内存是十六进制是 81 83 20 3B ......

从数据帧解析出的

opcode = 0x8

该粉丝不明白为什么解析出的值是0x8。

这个问题其实就是位域的问题和字节序的问题。

测试代码

废话不多说,直接写个测试代码

#include 
//简化的结构体
struct iphdr {
 unsigned char fin:1;
 unsigned char rsv:3;
 unsigned char opcode:4;
 unsigned char mask:1; 
 unsigned char payload:7;
 unsigned char a;
 unsigned char b;
};
main()
{
 struct iphdr t;
 unsigned char *s;
 
 //清空内存,防止有乱码
 memset(&t,0,4);
 //用指针指向结构体变量t
 s = (unsigned char*)&t;
 //通过数组访问的方式修改内存的值,因为hexdump解析的值是0x81 83,
 //所以0x81必为最低字节的内存的数据
 s[0] = 0x81;
 s[1] = 0x83;
 
 //打印出位域成员的值
 printf("fin:%d rsv:%d opcode:%d mask:%d paylod:%d \n",
  t.fin,t.rsv,t.opcode,t.mask,t.payload); 
}

执行结果:

fin:1,rsv:0,opcode:8,mask:1 paylod:65

分析:如下图所示,紫色部分是位域成员对应的内存中的实际空间布局,地址从左到右增加 第一个字节的0x81赋值后,各位域对应的二进制:

fin:1
rsv:0
opcode:1000
mask:1
paylod:1000001

如上图多少,内存的第1个字节是0x81,第2个字节是0x83;

第一个字节0x81的最低的bit[0]对应fin,bit[3:1]对应rsv,bit[7:4]对应opcode;第二个字节0x83的最低bit[0]对应mask,bit[7:1]对应payload。

所以结果显而易见。

2、什么是位域?

有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。

例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。

所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。

每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

struct 位域结构名
{ 
  位域列表
};

其中位域列表的形式为:

类型说明符 位域名:位域长度

如粉丝所举的实例:

struct iphdr {
 unsigned char fin:1;
 unsigned char rsv:3;
 unsigned char opcode:4;
 unsigned char mask:1; 
 unsigned char payload:7;
 unsigned char a;
 unsigned char b;
};

位域变量的说明与结构变量说明的方式相同。可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如:

struct bs
{
 int a:8;
 int b:2;
 int c:6;
}data;

说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明:

一个位域必须存储在同一个字节中,不能跨两个字节

如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:

struct bs
{
 unsigned a:4
 unsigned :0 /空域/
 unsigned b:4 /从下一单元开始存放/
 unsigned c:4
};

在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。

位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:

struct k
{
 int a:1
 int :2 /该2位不能使用/
 int b:3
 int c:2
};

从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。

这是位域操作的表示方法,也就是说后面加上“:1”的意思是这个成员的大小占所定义类型的1 bit,“:2”占2 bit,依次类推。当然大小不能超过所定义类型包含的总bit数。

一个bytes(字节)是8个 bit(二进制位)。例如你的结构体中定义的类型是u_char,一个字节,共8个bit,最大就不能超过8。32位机下,short是2字节,共16bit,最大就不能超过16,int是4字节,共32bit,最大就不能超过32. 依次类推。

位域定义比较省空间。

例如你上面的结构,定义的变量类型是u_char,是一字节类型,即8bit。

fc_subtype占了4bit,fc_type占2bit,fc_protocol_version占2bit,共8bit,正好是一个字节。

其他八个成员,各占1bit,共8bit,正好也是一个字节。

因此你的结构的大小如果用sizeof(struct frame_control)计算,就是2bytes。

3. 如何测试当前是大端还是小端?

计算机硬件有两种储存数据的方式:大端字节序(big endian)和小端字节序(little endian)。大端字节序:高位字节在前,低位字节在后,这是人类读写数值的方法。小端字节序:低位字节在前,高位字节在后。

0x1234567的大端字节序和小端字节序的写法如下图。

为什么会有小端字节序?

答案是,计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的。所以,计算机的内部处理都是小端字节序。

但是,人类还是习惯读写大端字节序。所以,除了计算机的内部处理,其他的场合几乎都是大端字节序,比如网络传输和文件储存。

计算机处理字节序的时候,不知道什么是高位字节,什么是低位字节。它只知道按顺序读取字节,先读第一个字节,再读第二个字节。

如果是大端字节序,先读到的就是高位字节,后读到的就是低位字节。小端字节序正好相反。

理解这一点,才能理解计算机如何处理字节序。

处理器读取外部数据的时候,必须知道数据的字节序,将其转成正确的值。然后,就正常使用这个值,完全不用再考虑字节序。

即使是向外部设备写入数据,也不用考虑字节序,正常写入一个值即可。外部设备会自己处理字节序的问题。

实例

仍然用上面的例子,但是做如下修改

#include 

struct iphdr {

 unsigned char fin:1;
 unsigned char rsv:3;
 unsigned char opcode:4;
 unsigned char mask:1; 
 unsigned char payload:7;   
};
main()
{
 struct iphdr t;

 unsigned short *s;

 memset(&t,0,2);

 s = (unsigned char *)&t;
 //注意,直接赋值0x8183,因为该常量必然和主机字节序一致,
 //小端:83给低字节,
 //大端:81给低字节
 *s = 0x8183;

 printf("fin:%d rsv:%d opcode:%d mask:%d paylod:%d \n",
  t.fin,t.rsv,t.opcode,t.mask,t.payload); 
}

执行结果:

fin:1 rsv:1 opcode:8 mask:1 paylod:64

由结果可知,收到的0x8183这个值与对应的的二进制关系:

fin:1
rsv:001
opcode:1000
mask:1
paylod:1000000

如上图多少,内存的第1个字节是0x83,第2个字节是0x81【和前面的例子不一样了,因为我们是直接赋值0x8183,而该常数是小字节序,所以低字节是0x83】;

可见:

低字节83给了 fin+rsv+opcode

所以,这说明了一口君的ubuntu是小端字节序。

4. 拓展例子

继续将结构体做如下修改,当位域成员大小加一起不够一个整字节的时候,验证各成员在内存中的布局。

#include 
struct iphdr {
 unsigned char fin:1;
 unsigned char opcode:4;
 unsigned char a;
 unsigned char b;
};
main()
{
 struct iphdr t;

 unsigned char *s;

 memset(&t,0,2);

 s = (unsigned short *)&t;

 t.fin = 1;
 t.opcode = 0xf;
 
 printf("%x\n",s[0]);  
}
fin:1
opcode:1111

内存中形式如下:

如果修改fin的值为0:

 t.fin = 0;

执行结果如下:

fin:0
opcode:1111

内存中形式如下:

5. 总结

大家遇到类似问题的时候,一定要写一些实例去验证,对于初学者来说,建议多参考上述实例。

相关推荐

想把TXT转换成PDF怎么转?试试这个小技巧

想把TXT转换成PDF怎么转?电子书是指以电子形式存储的书籍,其格式和传统的纸质书籍有所不同。目前常见的电子书格式主要包括EPUB、MOBI、AZW、PDF、TXT等。TXT是一种基本的文本文件格式,...

怎样在已有的pdf文档中加页或插入新页面?

当原始PDF文档需要更新或修订时,添加一页无疑是一种便捷灵活的解决方案,不仅能确保文档新增内容的及时呈现,还可巧妙规避对原有内容的过度干扰,从而维护PDF文档的连贯性与完整性。如果你还不清楚要如何进行...

PDF与word的区别,电脑如何编辑pdf文件?

众所周知,PDF是一种“特别”难编辑的格式,但小编却不这么认为。为什么呢?往下聊聊就知道了。PDF意为“可携带文档格式”,它以PostScript语言图象模型为基础,无论在哪种打印机上都可保证精确的颜...

pdf怎么旋转方向?分享3招旋转方法,简单易上手!

你是否遇到过需要旋转PDF文件方向的情况?例如,需要将PDF文档中的页面,进行顺时针或逆时针旋转,以便更好地阅读或编辑。...

什么软件可以免费翻译pdf?这几个翻译工具可以帮你搞定

我们都知道只要将文件保存成pdf格式,无论用什么设备去阅读,文件的排版基本不会出现混乱,所以现在越来越多的文献都会用pdf格式来保存。不过这就导致我们,当要去阅读国外文献的时候,得看一句翻译一句。还有...

使用deepseek开发自己的小程序1-word转PDF,小白专属-全程0代码

在日常办公中,我们经常需要将word文档转换成PDF文档,但是很多此类服务是需要付费的。下面我们介绍如何使用deepseek,让代码小白也可以拥有一款本地部署的,免费版,word转pdf,格式转换工具...

手机word怎么转pdf?教你3招,一键轻松转~

无论是学生族还是职场人,都免不了需要在手机上处理各种文档,尤其是Word文档。但在分享或传送时,需要往往需要将其转换成PDF格式。...

Word如何转化为PDF文件?这三个方法超级实用!

Word如何转化为PDF文件?PDF文档可以保护文档的格式和布局,因此是很多人共享文档的首选格式,为了不让Word文档格式错乱,很多小伙伴们在发送之前都会将Word文件转化为PDF格式,那么如何将Wo...

惊艳!PDF分割这么简单,电脑、手机、网页端都能1秒瞬间分割!

当我们浏览查阅大量PDF文件时,它们的长页面内容通常会令我们在查找所需信息的过程中,感到麻烦和困扰。实际上我们可以使用PDF分割功能对需要查看的页面进行筛选和划分,这可有效提高阅读效率及便利性。...

word怎么转化成pdf文件?9种超实用转换方法让你事半功倍!

word和pdf作为两大主流文档格式,几乎无处不在。在特定使用场景下,也常常需要将word转化为pdf,那如何进行转换呢?接着往下看你就知道了~一、为什么要将word转化为pdf1、保留原始格式,确保...

(速看)pdf转换成word的10个方法已整理,请查收

在我们日常的学习办公生活中,PDF文件已经不可或缺的一部分。无论是电子书籍、合同、报告还是任何其他重要文档,PDF格式以其稳定性和兼容性受到广泛欢迎。然而,PDF格式在编辑时却显得不够灵活,尤其是当我...

pdf文档怎么弄?超级简单的方法就是这个

pdf文档怎么弄?想把PDF文档识别出来相比打工人经常会问到,因为PDF特有的稳定性,是文件传输中的首选形式,它非常便于大家阅览,所以很多人都会想解决这个问题,小编有一个超级简单的方法,往下看看~...

如何导出PDF格式流程图?用对这个方法很简单

如何导出PDF格式流程图?相信很多人会再给客户传看资料的时候,往往需要将文件也好、流程图也好转成PDF格式,有人就会纠结怎么把流程图输出为PDF格式,其实方法很简单,选对网站,可以轻松解决这个问题,需...

怎样把电子书转换成PDF?看完这篇你就会了

随着科技的不断发展,越来越多的人习惯在网上阅读书籍。小伙伴们平时喜欢阅读电子书吗?电子书有很多种格式,例如TXT、PDF、MOBI、EPUB等格式,不同的阅读器所需要的电子书格式也各不相同,我们有时会...

本是烈女 缘何慈悲 | 女神学院(你本烈女我非无赖)

若说张震是王家卫调教出来的,那舒淇就一定是侯孝贤调教出来的。刚刚落幕的第68届戛纳电影节,侯孝贤导演凭借舒淇、张震、周韵等联袂主演的《刺客聂隐娘》一举拿下最佳导演奖。《聂隐娘》是舒淇与侯孝贤的第三次合...