C 结构体位域 bit field (小端)

2024-02-16 02:08
文章标签 结构 bit field 小端 体位

本文主要是介绍C 结构体位域 bit field (小端),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

运行环境为X86 64小端:

结构体中size最大的元素t0是int, 占四个字节,因此整个结构体是4字节对齐,结构体中的short是两字节对齐。

short占两个字节16bit,因此t1,t2,t3,t4共同占用short的两个字节。t5需要两字节对齐,单独占用两个字节。

因此整个结构体占用8个字节。

GDB通过x/8bx查看结构体8个字节,小端存放,高字节在高地址,低字节在低地址。

t0是0x00102030, 从低地址到高地址依次是: 0x30    0x20    0x10    0x00

t1,t2,t3,t4存放在同一个short两字节中,t4作为most significant,在内存中从低地址到高地址存放依次为t1,t2,t3,t4。

如果在GDB中以双字节打印这个short,显示顺序为t4t3t2t1,即0xdcba

如果以字节方式打印,由于short占用两个字节(高端字节t4t3,低端字节t2t1),高端字节存放在高地址,因此显示顺序为t2t1t4t3, 即0xba  0xdc

注意:不管何种方式打印,首先要明确的是t1t2t3t4是作为short类型存放的,然后再考虑各种方式打印这个short两字节的不同。

t5内容为0x000E, 小端存放为0x0E00

#include <stdio.h>
#include <string.h>typedef struct bit_field{unsigned int   t0;unsigned short t1 : 4;unsigned short t2 : 4;unsigned short t3 : 4;unsigned short t4 : 4;unsigned short t5 : 4;
}bf;void endian_check()
{int i = 0x1;unsigned char *p;p = (unsigned char *)&i;if (*p)printf("little endian\r\n");elseprintf("big endian\r\n");return;
}main()
{endian_check();printf("size of uint is: %d\r\n", sizeof(unsigned int));printf("size of ushort is: %d\r\n", sizeof(unsigned short));printf("size of bit_field structure is: %d\r\n", sizeof(bf));bf bf_test;memset(&bf_test, 0, sizeof(bf_test));bf_test.t0 = 0x102030;bf_test.t1 = 0x0A;bf_test.t2 = 0x0B;bf_test.t3 = 0x0C;bf_test.t4 = 0x0D;bf_test.t5 = 0x0E;
}

输出为:

little endian
size of uint is: 4
size of ushort is: 2
size of bit_field structure is: 8

 

通过GDB查看内存字节存放:

(gdb) p bf_test
$1 = {t0 = 1056816, t1 = 10, t2 = 11, t3 = 12, t4 = 13, t5 = 14}
(gdb) x/4hx &bf_test
0x7fffffffe230: 0x2030  0x0010  0xdcba  0x000e
(gdb) x/8bx &bf_test
0x7fffffffe230: 0x30    0x20    0x10    0x00    0xba    0xdc    0x0e    0x00

以下内容from http://mjfrazer.org/mjfrazer/bitfields/

How Endianness Effects Bitfield Packing

Hints for porting drivers.

Big endian machines pack bitfields from most significant byte to least.
Little endian machines pack bitfields from least significant byte to most.

When we read hexidecimal numbers ourselves, we read them from most significant byte to least. So reading big endian memory dumps is easer than reading little endian. When it comes to reading memory dumps of bitfields, it is even harder than reading integers.

Consider:

    union {unsigned short value;unsigned char byte[2];struct {unsigned short a : 4;unsigned short b : 4;unsigned short c : 4;unsigned short d : 4;} field;} u;

On a big endian machine, the first field is in the first nibble in memory. When we print out a memory dump's character hex values, say [ 0x12, 0x34 ], it is easy to see that a = 1, b = 2, c = 3 and d = 4.

On a little endian machine, a memory dump of [ 0x12, 0x34 ] would indicate that a = 2, b = 1, c = 4, and d = 3. This is because our 2-nibble, or 1 byte, hex value has transposed the pairs of nibbles. Remember that field a would go in the least significant bits, so if we set (a, b, c, d) = (1, 2, 3, 4) we would read the nibbles from least significant to most as 1 2 3 4, but the bytes as 0x21, 0x43. Interpreting this memory as a short gives us the value 0x4321.

These two figures illustrate how the nibble sized elements are packed into memory with the 16 bit field being laid out from MSB to LSB.

 

big endian examplelittle endian example
Big Endian LayoutLittle Endian Layout

注意:上图中

左图:对于大端来说,左侧为低地址,右侧为高地址。a为most significant, d为least significant

右图:对于小端来说,右侧为低地址,左侧为高地址。a为least significant, d为most significant

Now consider:

    union {unsigned short value;unsigned char byte[2];struct {unsigned short a : 1;unsigned short b : 2;unsigned short c : 3;unsigned short d : 4;unsigned short e : 5;} field;} v;

Again, the bits are pack from most significant on a big endian machine and least significant on a little endian machine. Interpreted as a short, the bitfield 'a' adds 0x0001 to 'value' on a little endian machine and 0x8000 on a big endian machine. The unused bit is left to the end of interpreting the struct, so it is the MSB on a little endian machine and the LSB on a big endian machine.

These two figures illustrate how the differently sized elements are packed into memory with the 16 bit field being laid out from MSB to LSB.

注意:上图中

左图:对于大端来说,左侧为低地址,右侧为高地址。a为most significant, d为least significant

右图:对于小端来说,右侧为低地址,左侧为高地址。a为least significant, d为most significant

 

参考:

http://mjfrazer.org/mjfrazer/bitfields/

 

这篇关于C 结构体位域 bit field (小端)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/713198

相关文章

使用Java实现通用树形结构构建工具类

《使用Java实现通用树形结构构建工具类》这篇文章主要为大家详细介绍了如何使用Java实现通用树形结构构建工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录完整代码一、设计思想与核心功能二、核心实现原理1. 数据结构准备阶段2. 循环依赖检测算法3. 树形结构构建4. 搜索子

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据

《mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据》文章主要介绍了如何从.frm和.ibd文件恢复MySQLInnoDB表结构和数据,需要的朋友可以参... 目录一、恢复表结构二、恢复表数据补充方法一、恢复表结构(从 .frm 文件)方法 1:使用 mysq

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

结构体和联合体的区别及说明

《结构体和联合体的区别及说明》文章主要介绍了C语言中的结构体和联合体,结构体是一种自定义的复合数据类型,可以包含多个成员,每个成员可以是不同的数据类型,联合体是一种特殊的数据结构,可以在内存中共享同一... 目录结构体和联合体的区别1. 结构体(Struct)2. 联合体(Union)3. 联合体与结构体的

Linux使用粘滞位 (t-bit)共享文件的方法教程

《Linux使用粘滞位(t-bit)共享文件的方法教程》在Linux系统中,共享文件是日常管理和协作中的常见任务,而粘滞位(StickyBit或t-bit)是实现共享目录安全性的重要工具之一,本文将... 目录文件共享的常见场景基础概念linux 文件权限粘滞位 (Sticky Bit)设置共享目录并配置粘

PostgreSQL如何查询表结构和索引信息

《PostgreSQL如何查询表结构和索引信息》文章介绍了在PostgreSQL中查询表结构和索引信息的几种方法,包括使用`d`元命令、系统数据字典查询以及使用可视化工具DBeaver... 目录前言使用\d元命令查看表字段信息和索引信息通过系统数据字典查询表结构通过系统数据字典查询索引信息查询所有的表名可

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c