- C语言编程教程
- C语言 - 首页
- C语言基础
- C语言 - 概述
- C语言 - 特性
- C语言 - 历史
- C语言 - 环境搭建
- C语言 - 程序结构
- C语言 - Hello World
- C语言 - 编译过程
- C语言 - 注释
- C语言 - 词法单元
- C语言 - 关键字
- C语言 - 标识符
- C语言 - 用户输入
- C语言 - 基本语法
- C语言 - 数据类型
- C语言 - 变量
- C语言 - 整数提升
- C语言 - 类型转换
- C语言 - 类型强制转换
- C语言 - 布尔值
- C语言中的常量和字面量
- C语言 - 常量
- C语言 - 字面量
- C语言 - 转义序列
- C语言 - 格式说明符
- C语言中的运算符
- C语言 - 运算符
- C语言 - 算术运算符
- C语言 - 关系运算符
- C语言 - 逻辑运算符
- C语言 - 位运算符
- C语言 - 赋值运算符
- C语言 - 一元运算符
- C语言 - 自增和自减运算符
- C语言 - 三元运算符
- C语言 - sizeof 运算符
- C语言 - 运算符优先级
- C语言 - 其他运算符
- C语言中的决策语句
- C语言 - 决策语句
- C语言 - if 语句
- C语言 - if...else 语句
- C语言 - 嵌套 if 语句
- C语言 - switch 语句
- C语言 - 嵌套 switch 语句
- C语言中的循环
- C语言 - 循环
- C语言 - while 循环
- C语言 - for 循环
- C语言 - do...while 循环
- C语言 - 嵌套循环
- C语言 - 无限循环
- C语言 - break 语句
- C语言 - continue 语句
- C语言 - goto 语句
- C语言中的函数
- C语言 - 函数
- C语言 - 主函数
- C语言 - 按值调用函数
- C语言 - 按引用调用函数
- C语言 - 嵌套函数
- C语言 - 变参函数
- C语言 - 用户自定义函数
- C语言 - 回调函数
- C语言 - 返回语句
- C语言 - 递归
- C语言中的作用域规则
- C语言 - 作用域规则
- C语言 - 静态变量
- C语言 - 全局变量
- C语言中的数组
- C语言 - 数组
- C语言 - 数组的特性
- C语言 - 多维数组
- C语言 - 将数组传递给函数
- C语言 - 从函数返回数组
- C语言 - 变长数组
- C语言中的指针
- C语言 - 指针
- C语言 - 指针和数组
- C语言 - 指针的应用
- C语言 - 指针运算
- C语言 - 指针数组
- C语言 - 指向指针的指针
- C语言 - 将指针传递给函数
- C语言 - 从函数返回指针
- C语言 - 函数指针
- C语言 - 指向数组的指针
- C语言 - 指向结构体的指针
- C语言 - 指针链
- C语言 - 指针与数组的区别
- C语言 - 字符指针和函数
- C语言 - 空指针
- C语言 - void 指针
- C语言 - 悬空指针
- C语言 - 解引用指针
- C语言 - 近指针、远指针和巨大指针
- C语言 - 指针数组的初始化
- C语言 - 指针与多维数组的区别
- C语言中的字符串
- C语言 - 字符串
- C语言 - 字符串数组
- C语言 - 特殊字符
- C语言中的结构体和联合体
- C语言 - 结构体
- C语言 - 结构体和函数
- C语言 - 结构体数组
- C语言 - 自引用结构体
- C语言 - 查询表
- C语言 - 点 (.) 运算符
- C语言 - 枚举 (enum)
- C语言 - 结构体填充和打包
- C语言 - 嵌套结构体
- C语言 - 匿名结构体和联合体
- C语言 - 联合体
- C语言 - 位域
- C语言 - typedef
- C语言中的文件处理
- C语言 - 输入 & 输出
- C语言 - 文件 I/O (文件处理)
- C语言预处理器
- C语言 - 预处理器
- C语言 - 预处理指令
- C语言 - 预处理器运算符
- C语言 - 宏
- C语言 - 头文件
- C语言中的内存管理
- C语言 - 内存管理
- C语言 - 内存地址
- C语言 - 存储类
- 其他主题
- C语言 - 错误处理
- C语言 - 可变参数
- C语言 - 命令执行
- C语言 - 数学函数
- C语言 - static 关键字
- C语言 - 随机数生成
- C语言 - 命令行参数
- C语言编程资源
- C语言 - 问答
- C语言 - 快速指南
- C语言 - 速查表
- C语言 - 有用资源
- C语言 - 讨论
C语言中的位域
当我们声明一个结构体或联合体类型时,结构体/联合体类型变量的大小取决于其各个元素的大小。您可以设置位的大小来限制大小,而不是使用默认的内存大小。指定的大小称为位域。
这是声明位域的语法:
struct { data_type elem : width; };
假设您的 C 程序包含许多在名为status的结构体中分组的 TRUE/FALSE 变量,如下所示:
struct { unsigned int widthValidated; unsigned int heightValidated; } status;
此结构体需要 8 字节的内存空间,但实际上,我们每个变量都只存储“0”或“1”。C 语言提供了一种更好的方法来利用此类情况下的内存空间。
如果您在结构体中使用此类变量,则可以定义变量的宽度,这告诉 C 编译器您只打算使用那么多字节。例如,上述结构体可以改写如下:
struct { unsigned int widthValidated : 1; unsigned int heightValidated : 1; } status;
上述结构体需要 4 字节的内存空间来存储status变量,但只使用 2 位来存储值。
示例
如果您最多使用 32 个变量,每个变量的宽度为 1 位,那么status结构体也将使用 4 个字节。但是,一旦您有 33 个变量,它将分配下一个内存槽,并将开始使用 8 个字节。
让我们检查以下示例以了解这个概念:
#include <stdio.h> /* define simple structure */ struct { unsigned int widthValidated; unsigned int heightValidated; } status1; /* define a structure with bit fields */ 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
位域声明
位域的声明在结构体内部具有以下形式:
struct { type [member_name] : width ; };
下表描述了位域的变量元素:
元素 | 描述 |
---|---|
类型 | 一个整数类型,它决定如何解释位域的值。 类型可以是int、signed int或unsigned int。 |
成员名称 | 位域的名称。 |
宽度 | 位域中的位数。“宽度”必须小于或等于指定类型的位宽。 |
使用预定义宽度定义的变量称为位域。位域可以容纳多个位;例如,如果您需要一个变量来存储 0 到 7 的值,则可以定义一个宽度为 3 位的位域,如下所示:
struct { unsigned int age : 3; } Age;
上述结构体定义指示 C 编译器变量“Age”将仅使用 3 位来存储值。如果您尝试使用超过 3 位,则它将不允许您这样做。
示例
让我们尝试以下示例:
#include <stdio.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; printf("Age.age : %d\n", Age.age); return 0; }
输出
编译上述代码时,将出现警告:
warning: unsigned conversion from 'int' to 'unsigned char:3' changes value from '8' to '0' [-Woverflow]|
执行时,将产生以下输出:
Sizeof(Age): 4 Age.age: 4 Age.age: 7 Age.age: 0
您可以在存储空间有限的情况下使用位域。当设备传输编码到多个位中的状态或信息时,位域也很有效。每当某些加密程序需要访问字节内的位时,都使用位域来定义数据结构。