精华内容
下载资源
问答
  • 2021-03-10 10:47:00

    随笔 - 30 文章 - 0 评论 - 36 阅读 - 11万
    C结构体之位域(位段)
    有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。
    一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

    struct 位域结构名
    {

    位域列表

    };
    其中位域列表的形式为:

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

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

    1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:

    struct bs
    {
    unsigned a:4
    unsigned b:5 /从下一单元开始存放/
    unsigned c:4
    }
    2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度。

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

    复制代码
    struct k
    {
    int a:1
    int :2 /无位域名,该2位不能使用/
    int b:3
    int c:2
    };
    复制代码
    二、位域的使用

    下面例子是参加一个公司(白领科技-青岛)的笔试遇到的,当时做错了,为了怕忘了,赶紧写下来。

    复制代码
    1 #include
    2 #include <memory.h>
    3 using namespace std;
    4 struct A
    5 {
    6 int a:5;
    7 int b:3;
    8 };
    9 int main(void)
    10 {
    11 char str[100] = “0134324324afsadfsdlfjlsdjfl”;
    12 struct A d;
    13 memcpy(&d, str, sizeof(A));
    14 cout << d.a << endl;
    15 cout << d.b << endl;
    16 return 0;
    17 }
    复制代码
    在32位x86机器上输出:

    $ ./langxun.exe
    -16
    1
    解析:在默认情况下,为了方便对结构体内元素的访问和管理,当结构体内的元素长度都小于处理器的位数的时候,便以结构体里面最长的元素为对其单位,即结构体的长度一定是最长的数据元素的整数倍;如果有结构体内存长度大于处理器位数的元素,那么就以处理器的位数为对齐单元。由于是32位处理器,而且结构体中a和b元素类型均为int(也是4个字节),所以结构体的A占用内存为4个字节。

    上例程序中定义了位域结构A,两个个位域为a(占用5位),b(占用3位),所以a和b总共占用了结构A一个字节(低位的一个字节)。

    当程序运行到14行时,d内存分配情况:

    高位 00110100 00110011 00110001 00110000 低位
    ‘4’ ‘3’ ‘1’ ‘0’
    其中d.a和d.b占用d低位一个字节(00110000),d.a : 10000, d.b : 001
    d.a内存中二进制表示为10000,由于d.a为有符号的整型变量,输出时要对符号位进行扩展,所以结果为-16(二进制为11111111111111111111111111110000)

    d.b内存中二进制表示为001,由于d.b为有符号的整型变量,输出时要对符号位进行扩展,所以结果为1(二进制为00000000000000000000000000000001)

    三、位域的对齐

    如果结构体中含有位域(bit-field),那么VC中准则是:

    1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

    2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

    3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式;

    系统会先为结构体成员按照对齐方式分配空间和填塞(padding),然后对变量进行位域操作

    更多相关内容
  • 文章主要对C语言结构体的位域知识进行详细介绍。
  • 位域的定义 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种...
  • 正是基于这种考虑,C语言又提供了一种叫做位域的数据结构。 在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域。请看下面的例子: struct bs{ unsigned m; unsigned n: 4; ...
  • 主要介绍了C++编程中的匿名类类型和位域,是C++入门学习中的基础知识,需要的朋友可以参考下
  • 位域 适用于Node.js和浏览器的易于使用的位域。 安装 对于Node.js或webpack项目,请使用NPM软件包管理器进行安装: npm install --save bitfields 要在没有捆绑程序的浏览器中使用,请在HTML中包含此脚本标签。 ...
  • 主要介绍了简单了解Java位域的一些知识,这个概念是在 Effective Java中了解到的, 可以通过EnumSet来代替位域这种方式表达,需要的朋友可以参考下
  • 浅析C语言位域和位段

    2020-09-05 02:29:51
    以下是对C语言中的位域和位段进行了详细的分析介绍,需要的朋友可以过来参考下
  • C++ 位域

    2019-08-13 01:23:24
    NULL 博文链接:https://jacky-dai.iteye.com/blog/2306126
  • 1200案例复位置位练习
  • 主要介绍了Java中EnumSet代替位域代码详解,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
  • 我们常用的x86结构都是小端模式,而大部分DSP,ARM也是小端模式,不过有些ARM是可以选择大小端模式。所以对于上面的maxHeight是应该以小端模式来存放,具体情况请看下面两表
  • 数据结构位域

    2015-08-13 16:47:54
    位域是c语言提供的一种数据结构,目的是为了节省存储空间
  • 结构扩展 structex提供了注释规则,该规则扩展了Go结构,以实现字节支持的数据帧的编码和解码。 structex旨在structex表示可直接嵌入代码中的行业标准数据格式的过程。 例子 给定SCSI查询数据的前三个字节T10 SCSI...
  • C 结构体位域.docx

    2019-09-10 09:54:08
    所谓“位域”是把一个字节中的二进位划分为几 个不同的区域,并说明每个区域的位数。本文档用例子描述了C结构体位域的应用,简单易懂,相信初学者很快就能掌握。
  • 聊一聊C语言位域/位段

    千次阅读 2022-03-05 17:53:09
    有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用 0 和 1 表示足以,也就是用一个二...正是基于这种考虑,C语言又提供了一种叫做位域的数据结构。

    目录

    1、概念和定义

    2、实例


    在做嵌入式开发的时候,我们经常会遇到这样的代码:

    struct
    {
      unsigned int widthValidated : 1;
      unsigned int heightValidated : 1;
    } status;

    这样定义结构体变量是什么意思呢?

    主要原因是:有些信息在存储时,只需占几个或一个二进制位(bit),并不需要占用一个完整的字节。例如,在存放一个开关量时,只有0和1两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言提供了一种数据结构,称为“位域”或“位段”。

    1、概念和定义

    位域:是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。

    位域定义与结构定义相仿,其形式为:

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

    其中位域列表的形式为:

    type [member_name] : width ;

    下面是有关位域中变量元素的描述:

    位域的使用和结构体成员的使用相同,其一般形式为:

    位域变量名.位域名
    位域变量名->位域名

    位域最大的作用就是节省存储空间,在本质上就是一种结构类型,不过其成员是按二进位分配的。例如以下案例:

    #include <stdio.h>
    #include <string.h>
     
    /* 定义简单的结构 */
    struct
    {
      unsigned int widthValidated;
      unsigned int heightValidated;
    } status1;
     
    /* 定义位域结构 */
    struct
    {
      unsigned int widthValidated : 1;
      unsigned int heightValidated : 1;
    } status2;
     
    int main( )
    {
       printf( "Memory size occupied by status1 : %d\n", sizeof(status1));
       printf( "Memory size occupied by status2 : %d\n", sizeof(status2));
     
       return 0;
    }

    代码被编译和执行时,它会产生下列结果:

    Memory size occupied by status1 : 8
    Memory size occupied by status2 : 4

    结构体status1是由正常的两个unsigned int类型变量组成,占用内存是8字节,结构体status2也是unsigned int类型变量,但是它仅使用了一个unsigned int类型内存的前2bit,实际上还有30bit没使用,所以占用内存是4字节。

    对于位域的定义有以下几点说明:

    • 一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:
    struct bs{
        unsigned a:4;
        unsigned  :4;    /* 空域 */
        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;
    };
    • 当相邻成员的类型相同时,如果它们的位宽之和小于类型的 sizeof 大小,那么后面的成员紧邻前一个成员存储,直到不能容纳为止;如果它们的位宽之和大于类型的 sizeof 大小,那么后面的成员将从新的存储单元开始,其偏移量为类型大小的整数倍。例如:
    #include <stdio.h>
    
    int main(){
        struct bs{
            unsigned m: 6;
            unsigned n: 12;
            unsigned p: 4;
        };
    
        printf("%d\n", sizeof(struct bs));
    
        return 0;
    }

    运行结果:

    4

    m、n、p 的类型都是 unsigned int,sizeof 的结果为 4 个字节(Byte),也即 32 个位(Bit)。m、n、p 的位宽之和为 6+12+4 = 22,小于 32,所以它们会挨着存储,中间没有缝隙。

    • 当相邻成员的类型不同时,不同的编译器有不同的实现方案,GCC 会压缩存储,而 VC/VS 不会。例如:
    #include <stdio.h>
    
    int main(){
        struct bs{
            unsigned m: 12;
            unsigned char ch: 4;
            unsigned p: 4;
        };
    
        printf("%d\n", sizeof(struct bs));
    
        return 0;
    }

    在 GCC 下的运行结果为 4,三个成员挨着存储;在 VC/VS 下的运行结果为 12,三个成员按照各自的类型存储(与不指定位宽时的存储方式相同)。

    • 如果成员之间穿插着非位域成员,那么不会进行压缩。 例如:
    struct bs{
        unsigned m: 12;
        unsigned ch;
        unsigned p: 4;
    };

    在各个编译器下 sizeof 的结果都是 12。

    注意:位域成员往往不占用完整的字节,有时候也不处于字节的开头位置,因此使用&获取位域成员的地址是没有意义的,C语言也禁止这样做。地址是字节(Byte)的编号,而不是位(bit)的编号。 

    2、实例

    通过一个示例,加深对位域的理解和应用:

    #include <stdio.h>
    #include <string.h>
     
    struct
    {
      unsigned int age : 3;
    } Age;
     
    int main( )
    {
       Age.age = 4;
       printf( "Sizeof( Age ) : %d\n", sizeof(Age) );
       printf( "Age.age : %d\n", Age.age );
     
       Age.age = 7;
       printf( "Age.age : %d\n", Age.age );
     
       Age.age = 8; // 二进制表示为 1000 有四位,超出
       printf( "Age.age : %d\n", Age.age );
     
       return 0;
    }

    当上面的代码被编译时,它会带有警告,当上面的代码被执行时,它会产生下列结果:

    Sizeof( Age ) : 4
    Age.age : 4
    Age.age : 7
    Age.age : 0

    当执行到Age.age = 8;时,二进制表示为:1000 有四位,超出位域,所以会提示警告。

    展开全文
  • 位域 bit field

    2021-02-12 03:07:17
    一、位域有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据...

    一、位域

    有些信息在存储时,并不需要占用一个完整的字节,

    而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1      两种状态,

    用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几

    个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位

    域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

    struct      位域结构名

    {      位域列表      };

    其中位域列表的形式为:      类型说明符      位域名:位域长度

    例如:

    struct      bs

    {

    int      a:8;

    int      b:2;

    int      c:6;

    };

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

    struct      bs

    {

    int      a:8;

    int      b:2;

    int      c:6;

    }data;

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

    1.      一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:

    struct      bs

    {

    unsigned      a:4

    unsigned      :0      /*空域*/

    unsigned      b:4      /*从下一单元开始存放*/

    unsigned      c:4

    }

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

    2.      由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。

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

    struct      k

    {

    int      a:1

    int      :2      /*该2位不能使用*/

    int      b:3

    int      c:2

    };

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

    二、位域的使用

    位域的使用和结构成员的使用相同,其一般形式为:      位域变量名·位域名      位域允许用各种格式输出。

    main(){

    struct      bs

    {

    unsigned      a:1;

    unsigned      b:3;

    unsigned      c:4;

    }      bit,*pbit;

    bit.a=1;

    bit.b=7;

    bit.c=15;

    printf("%d,%d,%d\n",bit.a,bit.b,bit.c);

    pbit=&bit;

    pbit->a=0;

    pbit->b&=3;

    pbit->c|=1;

    printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c);

    }

    上例程序中定义了位域结构bs,三个位域为a,b,c。说明了bs类型的变量bit和指向bs类型的指针变量pbit。这表示位域也是可以使用指针的。

    程序的9、10、11三行分别给三个位域赋值。(

    应注意赋值不能超过该位域的允许范围)程序第12行以整型量格式输出三个域的内容。第13行把位域变量bit的地址送给指针变量pbit。第14行用指针

    方式给位域a重新赋值,赋为0。第15行使用了复合的位运算符"&=",      该行相当于:

    pbit->b=pbit->b&3位域b中原有值为7,与3作按位与运算的结果为3(111&011=011,十进制值

    为      3)。同样,程序第16行中使用了复合位运算"|=",      相当于:

    pbit->c=pbit->c|1其结果为15。程序第17行用指针方式输出了这三个域的值。

    这也是在ChinaUnix上看了几篇关于C语言'位域(Bit

    Fields)'的帖子之后,才想写下这篇文章的。其实在平时的工作中很少使用到'位域',我是搞服务器端程序设计的,大容量的内存可以让我毫不犹豫的任

    意'挥霍'^_^。想必搞嵌入式编程的朋友们对位域的使用应该不陌生吧。这里我也仅仅是凭着对C语言钻研的兴趣来学习一下'位域'的相关知识的,可能有些

    说法没有实践,缺乏说服力。

    具体也不是很清楚当年C语言的创造者为什么要加入位域这一语法支持,那是太遥远的事情了,我们不需要再回顾了,既然大师们为我们创造了它,我们使用便是了。

    毋庸置疑,位域的引入给用户的最大的好处莫过于可以有效的利用'昂贵'的内存和操作bit的能力了。而且这种操作bit位的能力很是方便,利用结构体域名即可对这些bit进行操作。例如:

    struct      foo      {

    int      a      :      1;

    int      b      :      2;

    short      c      :      1;

    };

    struct      foo      aFoo;

    aFoo.a      =      1;

    aFoo.b      =      3;

    aFoo.c      =      0;

    通过结构体实例.域名即可修改某些bit得值,这些都是编译器的'甜头'。当然我们也可以自己通过一些'掩码'和移位操作来修改这些bit,当然如果不是十分需要,我们是不需要这么做的。

    位域还提供一种叫'匿名'位域的语法,它常用来'填缺补漏',由于是'匿名',所以你不能像上面那样去访问它。如:

    struct      foo1      {

    int      a      :      1;

    int          :      2;

    short      c      :      1;

    };

    在foo1的成员a和c之间有一个2      bits的匿名位域。

    在foo结构体的定义中,成员a虽然类型为int,但是它仅仅占据着4个字节中的一个bit的空间;类似b占据2个bit空间,但是b到底是占据第一个

    int的2个bit空间呢还是第二个int的2个bit空间呢?这里实际上也涉及到如何对齐带有'位域'的结构体这样一个问题。我们来分析一下。

    我们再来看看下面两个结构体定义:

    struct      foo2      {

    char            a      :      2;

    char            b      :      3;

    char            c      :      1;

    };

    struct      foo3      {

    char            a      :      2;

    char            b      :      3;

    char            c      :      7;

    };

    我们来打印一下这两个结构体的大小,我们得到的结果是:

    sizeof(struct      foo2)      =      1

    sizeof(struct      foo3)      =      2

    显然都不是我们期望的,如果按照正常的内存对齐规则,这两个结构体大小均应该为3才对,那么问题出在哪了呢?首先通过这种现象我们可以肯定的是:带有'位

    域'的结构体并不是按照每个域对齐的,而是将一些位域成员'捆绑'在一起做对齐的。以foo2为例,这个结构体中所有的成员都是char型的,而且三个位

    域占用的总空间为6      bit      但是三个成员位域所占空间之和为9      bit      >      8      bit(1      byte),个人认为这句话应该改为:但是Foo3的前两个成员所占空间是2+3=5,所以第一个字节只剩下8-5=3,不够存放第三个成员的7个字节,而规则要求,不允许成员跨字节存放,所以只能另外将此7字节单独分配,故又占了一个字节,这里位域是不能跨越两个成员基本类型空间的,这时编译器将a和b两个成员'捆绑'按照char做对齐,而c单独拿出来以char类型做对齐,这样实际上在b和c之间出现了空隙,但这也是最节省空间的方法了。我们再看一种结构体定义:

    struct      foo4      {

    char            a      :      2;

    char            b      :      3;

    int      c      :      1;

    };

    在foo4中虽然三个位域所占用空间之和为6      bit

    通过上面的例子我们发现很难总结出很规律性的东西,但是带有'位域'的结构体的对齐有条原则可以遵循,那就是:"尽量减少结构体的占用空间"。当然显式的使用内存对齐的机会也并不多。^_^

    展开全文
  • C语言位域

    2021-05-19 07:41:47
    在求职笔试中,C中的位域是一个常考点,特别是在嵌入式软件中更常见。位域的最大好处是可以根据自己需要定制位数,从而节省空间,例如:嵌入式编程稀缺的内存资源。还有在网络通讯中,对头信息部分的结构定义也常...

    在求职笔试中,C中的位域是一个常考点,特别是在嵌入式软件中更常见。位域的最大好处是可以根据自己需要定制位数,从而节省空间,例如:嵌入式编程稀缺的内存资源。还有在网络通讯中,对头信息部分的结构定义也常用到位域,少传一位是一位啊。

    这里来分析EMC的一道笔试题(07年招聘试题):

    1

    typedef struct

    bitstruct 2 { 3 int b1:5; 4 int :2; 5 int b2:2; 6 }bitstruct; 7 int main(int argc, char

    *argv[]) 8 { 9 bitstruct b; 10

    printf("%d\n",sizeof(bitstruct));

    11

    memcpy(&b,"EMC

    Examination",sizeof(b));

    12

    printf("%d,%d\n",b.b1,b.b2); 13

    return

    0; 14

    }

    请问在little-endian systems(系统默认的存放顺序)中,输出结果是什么?

    答案是

    45,-2;

    所需知识点:

    1.位域的概念和特点

    C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”(bit

    field)。(1)位段成员的类型必须指定为unsigned或int类型;(2)若某一位段要从另一个字开始存放,用:0长度为0的空位段,作用就是使下一个位段从下一个存储单位(视不同编译系统而异)开始存放;(3)一个位段必须存储在同一存储单元中,不能跨两个单元;(4)可以定义无名字段例如":2";(5)位段的长度不能大于存储单元的长度,也不能定义位段数组;(6)位段可以用整形格式符输出;(7)位段可以在数值表达式中引用,它会被系统自动地转换成整形数。[1][3]

    2.Little-endiansystems的内存布局特点

    先问一个问题:Endian这个词是什么意思?

    “endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。

    我们一般将endian翻译成“字节序”,将big

    endian和little

    endian称作“大尾”和“小尾”。这也在当今的CPU派别中一样存在。Motorola的PowerPC系列CPU采用的Big-endian,

    Intel的X86系列CPU采用的是Little-endian。Little-endian的特点是高高低低,即高位地址存放最高有效字节,低位地址存放最低有效字节;而Big-endian正好相反。下面用图的方式说明起来更直观,例如0x12345678(特别注意,这是单个数,不是字符串,如果是字符串就不一定这样了。之前没有特别注意这点,害的我多花了冤枉时间)。

    Big Endian

    低地址高地址----------------------------------------->

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    | 12 | 34 | 56 | 78 |

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    Little

    Endian

    低地址高地址----------------------------------------->

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    | 78 | 56 | 34 | 12 |

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    上面的字节序的不同,在单机的操作中没有问题,因为一台单机就是采用单一的字节序嘛!但是在两个不同的主机进行协作时,就会出现问题了;另外在网络通讯中也同样会出现问题,详细参考[2]

    就单个字节而言,也会有这样的问题:比特序有差别吗?

    也分成两种序,如果我们处理的基本单位是字节以上的话,对此就不必担心了,因为CPU存储操作的最小单元是字节,所以比特位的顺序对我们来就是透明的,我们在读取某个字节时,不管它用的是Big

    endian 还是Little

    endian,我们读到的都是一个同样的字节,只不过硬件在读写时的顺序,一个是从高到底另一个是从低到高,对我们的使用不产生影响。但是如果涉及到位域的存放问题,还是要特别小心,上面这道题就是一个非常的好的例子。

    Big Endian

    msb lsb

    ---------------------------------------------->

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    Little

    Endian

    lsb msb

    ---------------------------------------------->

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 |

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    3.memcpy()与strcpy()的区别

    这个问题很简单,可以想象成这样:memcpy的基本单位是位,strcpy的基本单位是字符。所以,memcpy会根据提供的长度完全按位拷贝,而strcpy是两个字符串之间的拷贝。

    回来原来的问题上,在采用little

    endian的BUS64中,struct

    bitstruct在没涉及到高低位问题时,也就是我们平时常会画出的一种形式是:

    {b1 b1 b1 b1 b1 Ø Ø b2 b2 Ø Ø Ø

    Ø Ø Ø Ø ØØØØØØØØ ØØØØØØØØ};

    在内存中的实际布局是:

    低地址高地址-------------------------------------------------------------->

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    |b2Ø Øb1

    b1b1 b1

    b1|Ø Ø Ø Ø Ø Ø

    Ø b2|ØØØØØØØØ |ØØØØØØØØ|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    Ø表示空填充,这当中包含一个原则:一个位域的存放不可以跨字存放,但可以跨字节存储;这里采用的比特续也是little

    endian,说明了比特序对操作也是有影响的嘛!

    memcpy按位拷贝“EMC Examination”到b中,一个字符是8位; 又因为sizeof(b)=4,所以只写入"EMC

    "。"EMC "对应的位序列是:{0100 0101 0100

    1101 0100 0011 0010

    0000},从这里写到内存里的形式是:(在这里不要被little

    endian给迷惑了,E不是放在高地址,参看上面红色的特别注意)

    低地址高地址-------------------------------------------------------------->

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    |b2Ø

    Øb1

    b1b1 b1

    b1|Ø

    Ø Ø Ø Ø Ø Øb2|ØØØØØØØØ|ØØØØØØØØ||0 1 0 0 0 1 0 1|0 1 0 0 1 1

    0 1|0100

    0011|0010

    0000|

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+printf("%d,%d\n",b.b1,b.b2);读出来的b1是00101,它的值是5;

    b2是10,转换成十进制是-2。到了这一步,似乎题目已经解答出来了,但还有两个地方有疑惑:

    1.struct bitstruct在内存中的位存放顺序是这样的么?

    低地址高地址-------------------------------------------------------------->

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    |b2Ø

    Øb1

    b1b1 b1

    b1|Ø

    Ø Ø Ø Ø Ø Øb2|ØØØØØØØØ|ØØØØØØØØ|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    2.memcpy函数在按位拷贝时的拷贝顺序是这样的么?

    低地址高地址-------------------------------------------------------------->

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|01000101|01001101|0100

    0011|0010

    0000|

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    关于上面两个问题的验证工作留给路过的朋友来做:-P ..... 欢迎批评指正

    注解:转载自(忘了什么地方)

    展开全文
  • C语言 位域的使用

    2021-06-09 10:52:19
    目录什么是位域位域的定义位域的使用使用位域的注意点(重要)实际应用 什么是位域 有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用...
  • 1、讲解位域结构体的原理和使用方法以及字节对齐问题; 2、讲解联合的概念以及联合体成员变量的内存分布;

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,180
精华内容 7,672
关键字:

位域

友情链接: PBSHR126 3506.zip