C 中的位域
在本篇文章中,我们将学习 C 语言中的位域。
我们将从位域开始讨论。 接下来我们将讨论位域存储,接着是C语言中位域的语法。
最后,我们将看到一个具有不同数据类型的位域,以了解内部具有位域的结构所占用的最小和最大空间。
C 中的位域
编程中的位域是一种独特的数据结构,可以帮助程序员节省内存。 位字段允许将内存分配给位结构。
让我们考虑一个只有黑白两种颜色的纯黑白图像。 我们只需要存储两个值:0 或 1。
考虑一个 100x100 的小图像,将屏幕与每个维度的数千个像素进行比较。 图像中将有一万个像素。
在标准数据类型中,你可以选择C语言的unsigned char数据类型,它只占用一个字节; 但是,要保存一张纯黑白图像,则需要 10000 字节的内存。
使用位字段,您可以在一个字节中保存八个像素(1 个字节中有 8 个位)。 这意味着您将需要大约 1250 个字节而不是 10000 个。
这只是一个例子; 这并不意味着您可以仅在图像的情况下节省空间。 在一些有数千名考生出现的考试中,您只需要一位来存储通过/未通过信息; 否则,选项是为每个候选者使用一个字节。
C 中的位域存储
考虑以下结构来开始对位域存储的讨论:
struct {
unsigned char is_married;
unsigned char is_graduated;
} status0;
这个结构需要两个字节的内存空间; 但是,我们必须在两个字段中存储 0 或 1。 让我们继续寻找一种更好的节省空间的方法。
我们将从语法到代码详细了解位域。
在 C 语言中,我们有一个特定的语法来告诉每个变量所需的位数:
struct{
type [variable_name] : size ; // Size will be in bits
}
重要的是要注意此语法可用于结构。 在这里,类型是任何数据类型,如 int、char、short、unsigned char 等。
您已经很清楚 C 语言中的合法变量名称。 冒号是语法的一部分,在变量名和大小之间是必需的,最后,大小是所需的位数。
接下来可能会让您感到惊讶的是结构的大小和位大小。 请参见以下代码:
#include <stdio.h>
struct {
unsigned char is_married;
unsigned char is_graduated;
} status0;
struct {
unsigned char is_married:1;
unsigned char is_graduated:1;
} status1;
int main( ) {
printf( "Memory size occupied by status1 : %ld bytes\n", sizeof(status0));
printf( "Memory size occupied by status1 : %ld bytes\n", sizeof(status1));
return 0;
}
输出是:
Memory size occupied by status1 : 2 bytes
Memory size occupied by status1 : 1 bytes
在输出中,第一个结构占用 2 个字节(即每个字段 1 个字节),这是非常合乎逻辑的。 但是,第二个输出占用 1 个字节; 您可能期望 2 个字节或位。
问题是,为什么是一个字节? 逻辑是数据类型将根据 C 语言的例程定义占用一个字节。
但是,以位为单位指定大小允许程序员声明另外 7 个字段,每个字段为 1 位。
对于 1 个字节,总位数应保持小于等于 8 位。 否则,将消耗 2 个字节的存储空间。
请参阅以下代码:
#include <stdio.h>
struct {
unsigned char a:1;
unsigned char b:7;
} status0;
struct {
unsigned char a:1;
unsigned char b:1;
unsigned char c:1;
unsigned char d:1;
unsigned char e:1;
unsigned char f:1;
unsigned char g:1;
unsigned char h:1;
} status1;
int main( ) {
printf( "Memory size occupied by status1 : %ld\n", sizeof(status0));
printf( "Memory size occupied by status1 : %ld\n", sizeof(status1));
return 0;
}
输出结果如下:
Memory size occupied by status1 : 1
Memory size occupied by status1 : 1
让我们看下一个示例,其中位数增加了:
#include <stdio.h>
struct {
unsigned char a:3;
unsigned char b:7;
unsigned char c:7;
} status0;
struct {
unsigned char a:1;
unsigned char b:1;
unsigned char c:1;
unsigned char d:1;
unsigned char e:1;
unsigned char f:1;
unsigned char g:1;
unsigned char h:1;
unsigned char i:1;
unsigned char j:1;
} status1;
int main( ) {
printf( "Memory size occupied by status1 : %ld\n", sizeof(status0));
printf( "Memory size occupied by status1 : %ld\n", sizeof(status1));
return 0;
}
输出结果如下:
Memory size occupied by status1 : 3
Memory size occupied by status1 : 2
在第一个结构中,总位数为 3+7+7=17,大于16比特(2字节)。 因此,将消耗 3 个字节。
在第一行输出中也可以看到相同的内容。
在第二个结构中,我们有 10 个字段,每个字段为 1 位,这需要 10 位; 因此,它将消耗两个字节。 同样,第二行输出证实了这个概念。
C 中 short 数据类型的位域
人们可能会认为需要 unsigned char
才能使用位域。 我们也可以将位域与其他数据类型一起使用。
在这里,我们考虑使用 short
数据类型来演示并更好地掌握位域的概念。
考虑以下代码:
#include <stdio.h>
struct {
unsigned short a:3;
} status0;
struct {
unsigned short a:3;
unsigned short b:9;
unsigned short c:4;
} status1;
int main( ) {
printf( "Memory size occupied by status1 : %ld\n", sizeof(status0));
printf( "Memory size occupied by status1 : %ld\n", sizeof(status1));
return 0;
}
输出结果如下:
Memory size occupied by status1 : 2
Memory size occupied by status1 : 2
在这两个结构中,消耗的内存都是 2 个字节,因为 short 需要 2 个字节。 因此,所需的最小内存为 2 个字节。
但是,多个字段可能总共消耗 16 位(如第二个结构中所示),大小将保持为 2 字节。
如果位数从 16 开始增加,接下来的两个字节的 short 数据类型将被自动覆盖,结果将消耗四个 4。
让我们看看下面的 C 程序:
#include <stdio.h>
struct {
unsigned short a:6;
unsigned short b:6;
unsigned short c:7;
} status1;
int main( ) {
printf( "Memory size occupied by status1 : %ld\n", sizeof(status1));
return 0;
}
此处,总位数为 6+6+7=19,因此输出为:
Memory size occupied by status1 : 4
请注意
,内存逐字节增加,因为char
具有单字节存储; 而在short
的情况下,内存增加了两个字节,因为根据定义,short
有两个字节的存储空间。
C 中具有多种数据类型的位域
现在,是时候讨论位域存储要求,以防结构具有两种或多种数据类型。 在这种情况下,所需的最小字节数是结构中最大数据类型所需的最大空间。
比如一个结构体有 short
和 char
成员,最大的类型是short,需要2个字节; 整个结构至少需要两个字节。
在 int & short
的情况下,int 是最大的类型; 因此,整个结构需要 4 个字节。 让我们借助以下代码示例来演示这个概念:
#include <stdio.h>
struct {
unsigned short a:6;
unsigned int b:6;
} status1;
struct {
unsigned long long a:6;
unsigned int b:6;
unsigned short c:6;
} status2;
int main( ) {
printf( "Memory size occupied by status1 : %ld\n", sizeof(status1));
printf( "Memory size occupied by status1 : %ld\n", sizeof(status2));
return 0;
}
输出结果如下:
Memory size occupied by status1 : 4
Memory size occupied by status1 : 8
在第一个结构中,int 是最大的数据类型; 因此,第一行输出显示 4 字节结构大小。
在第二个结构中,long long
是主导类型,因此输出的第二行显示该结构的八个字节大小。
最后,在多个数据大小的情况下增量会很简单; 增量步长是等于最大类型结构中的字节数。
让我们看一下下面的代码以获得更好的理解:
#include <stdio.h>
struct {
unsigned short a:6;
unsigned int b:30;
unsigned long long c:50;
} status1;
int main( ) {
printf( "Memory size occupied by status1 : %ld\n", sizeof(status1));
return 0;
}
该结构有 50+30+6=86 位,而 8 个字节有 64 位。 因此,此结构需要双倍空间,如下面的输出所示:
Memory size occupied by status1 : 16
我们需要 16 个字节,其中 id 8+8 个字节。
总结
如果我们在程序中使用多位字段,我们可以节省空间。 我们可以在声明时指定一个结构体成员变量的位数。
结构的最小大小是结构中最大数据类型所需的最大字节数。
如果单个或多个字段共同消耗的位数超过结构中最大类型的大小,则消耗的内存将是最大内存类型大小的倍数。
相关文章
在 C 语言中使用 typedef enum
发布时间:2023/05/07 浏览次数:181 分类:C语言
-
本文介绍了如何在 C 语言中使用 typedef enum。使用 enum 在 C 语言中定义命名整数常量 enum 关键字定义了一种叫做枚举的特殊类型。
C 语言中的 extern 关键字
发布时间:2023/05/07 浏览次数:114 分类:C语言
-
本文介绍了如何在 C 语言中使用 extern 关键字。C 语言中使用 extern 关键字来声明一个在其他文件中定义的变量
C 语言中的 #ifndef
发布时间:2023/05/07 浏览次数:186 分类:C语言
-
本文介绍了如何在 C 语言中使用 ifndef。在 C 语言中使用 ifndef 保护头文件不被多次包含 C 语言中的头文件用于定义同名源文件中实现的函数的接口。