搜索
写经验 领红包

c语言中的位段详解是什么(c语言位运算代码)

导语:C语言中的位段详解

c语言中的位段详解是什么(c语言位运算代码)

我们前面介绍过位运算,我们就可以对位进行所有类型的很高级的运算,很高级哦!我们不在局限于对数据类型整体操作,这样很麻烦,有时很有局限性,而且还有可能很浪费内存,比如你想要一个标志位,就比如布尔真假条件的标志,其实我们只需要一个位就可以表示了,1或0,如果呢,我们声明一个char类型来用作标志位变量,我们知道大多数计算机上char占用一个字节(8位),这就造成了内存浪费,当然了,几个看不出来,要是在一个大型程序中有若干标志位,那么浪费的内存就不少了。在C语言中如果不需要整个字节或字来表示数据,可以有两种方式实现,一种是,在int中通过我们前面介绍过的位运算来访问修改其中的位,第二就是今天将要介绍的位段,下面我们就从两种方式讲起,看看位段相比第一种到处理这种问题时优势在哪里。

一、运用位运算:

比如我们在某一大型程序中,希望将四个数据值打包到一个字中,这四个值分别为两个标志为记为f1、f2,一个数值为0到255即占用一个字节(8位)记为n,还有一个数值为0到100000,即占用18位记为nl,下面简单看一下其中的布局,不管大端还是小端:

首先是两个标志位各占用一个位,接着是0到255的数据值,占用了8位,18位是存放较大的数值。这四个数据总共占用内存为28个字节,因此可以使用一个整型变量来存放这4个数值,整型变量一般为32位,因此会有4个位空下来,由此,我们可以知道,前四个位为空不用,接下来为两个标志位各占一个位,紧随其后是8个位,用于存放0到255数值,剩下来就存放较大数值。

上面我们用usigned int wd来存储上面的四个数据,可以通过位运算来操作上面的数据。比如我们需要将一个较小的数值n设置为98,我们可以这样,首先把无符号整数98左移18位,为大数值让出空间,然后再或上wd,就可以了,因此有:

wd |= 98<<18

就可设置完成,对于任何一个数a,我们可以这样设置,为了确保任意数值a的范围在0到255之间,我们可以使用a&0xff,这样就避免数值过大,会改变前面的标志位等其他数值,保险一点我们有:

wd |= (a&0xff)<<18

但是这里有一个问题,n每个位必须为0,如果不为0就会出现错误,因此我们还需要进行将n清零操作,因此我们有:

wd &= ~(0xff<<18)

就可以使n清零,然后再结合上面的分析得到:

wd = (wd & ~(0xff<<18)) | ((a&0xff)<<18)

可以看出就这么一个简单的操作就这么繁琐,看来用这种方式有点不太好,下面呢!我们就介绍一种比较简单的方法,C语言提供位段的构造,用于定义一种打包信息的构造,下面就具体介绍一下。

二、位段:

说到打包,那么自然而然就会想到结构体,因此位段是定义在一个结构体当中,并加上特殊语法组合而成,允许为其加上位段名称,成员的一般形式为:

类型 名称 :段位所占二进制位数

类型只能是int、unsigned int、signed int三种类型,不可以是其他类型,如什么char、float等,是不可以的。

名称可选,可要可不要,视情况而定。

冒号后面的二进制位数表示该数值占用多少位,比如上面的标志位占1位,那么数值就为1,n占八位数值就是8。

我们上面举的类子可以使用位段表示如下:

struct wd{unsigned int :4;unsigned int f1:1;unsigned int f2:1;unsigned int n:8;unsigned int nl:18;};

上面结构体中有5个成员,第一个成员没有名称没法引用,占用了4个位,后面两个标志位长度都被指定为占用1个位,紧接着n被指定为占用8个位,nl被指定为18个位。

这样就有好处了,可以通过正常结构体引用成员的便捷方法来访问字段,那么上面要想修改或访问上面的n数值就不用那么繁琐了,如我们可以把98直接赋给成员n。

struct wd w1;w1.n=98;

怎样变得很简单吧,根本就不需要用位运算那样复杂,更不用担心被赋值的数值过大,因为再大得数也只有第8位赋给w1.n。

当然要是提取其中的数值也很简单,如

a=w1.n;

要是位段在普通表达式中使用,那么会自动转换为相应的整数,很方便。你也可以通过标志位进行判断语句中,如if(w1.f1)是完全可行的。

使用位段需要注意以下几点:

1、我们不能保证位段内部是自左向右还是自右向左分配,如果我们处理相同程序或相同机器的话,这不会成为问题,但是如果确实要进行这种处理,我们就需要知道字段是如何分配的,然后再进行适当声明。

2、位段类型只能是int、unsigned int、signed int三种类型。

3、无名的位段不能访问,但是它会占用指定的内存空间,成员中占用0位的位段,只能是无名位段,0长的无名位段有一个作用,就是将结构体中的下一个字段强制对齐到单元边界的其实位置。

4、位段占用的二进制位不能大于基本整数类型所能表示的最大位数。

5、位段不能具有纬度,也就是说不能使用位段数组。

6、不能获取位段的地址,也就是说不会有指向位段的指针。

7、对位段进行赋值时,最好不要超过位段所能表示的最大值。

8、C编译器不会为了优化内存空间而去调整位段定义。

9、如果一个位段存储单元能够存放下所有成员,那么所有成员只能存放在一个位段存储单元中。如果一个位段存储单元不能存放下所有成员,那么剩余的位段将从下一个位段存储单元开始存放。

10、如果一个位段结构体中只有一个无名0位的成员,那么只占用0或1字节的空间,其他情况下至少占用一个位段存储单元的大小。

当然了,位段的结构体中也可以包含其他普通数据类型。

解释至此,我想大家应该能掌握差不多了吧。

下面对上面的四个问题做一个提示:

问题1:

对于可变长结构体,第二个元素其实不算在结构体当中,只不过可以通过结构体变量引用而已。

问题2:

考察static关键字已经extern的知识,自己可以去找资料。

问题3:

要知道strlen是以空字符'\0'以结束标志,以及数据在内存中的组织方式,用纸画一画,写一写。

问题4:

要了解指针,&num是什么意思,然后加上1,其实是跳过了怎个数组。

今天暂时只介绍到这里。

本文内容由快快网络小薇创作整理编辑!