C语言九:位域(位域声明、位域的定义和位域变量的说明、对于位域定义的几点说明:、位域的使用)、typedef(typedef vs #define)、强制类型转换(整数提升、常用的算术转换)

位域

如果程序的结构中包含多个开关量,只有 TRUE/FALSE 变量,如下:

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

这种结构需要 8 字节的内存空间,但在实际上,在每个变量中,我们只存储 0 或 1。在这种情况下,C 语言提供了一种更好的利用内存空间的方式。如果您在结构内使用这样的变量,您可以定义变量的宽度来告诉编译器,您将只使用这些字节。例如,上面的结构可以重写成:

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

现在,上面的结构中,status 变量将占用 4 个字节的内存空间,但是只有 2 位被用来存储值。如果您用了 32 个变量,每一个变量宽度为 1 位,那么 status 结构将使用 4 个字节,但只要您再多用一个变量,如果使用了 33 个变量,那么它将分配内存的下一段来存储第 33 个变量,这个时候就开始使用 8 个字节。

实例:

#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

位域声明

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

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

典型的实例:

  • 用 1 位二进位存放一个开关量时,只有 0 和 1 两种状态。
  • 读取外部文件格式——可以读取非标准的文件格式。例如:9 位的整数。

位域的定义和位域变量的说明

定义:

struct 位域结构名 
{

 位域列表

};

位域列表:

type [member_name] : width ;
元素描述
type只能为 int(整型),unsigned int(无符号整型),signed int(有符号整型) 三种类型,决定了如何解释位域的值。
member_name位域的名称。
width位域中位的数量。宽度必须小于或等于指定类型的位宽度。

带有预定义宽度的变量被称为位域。 

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

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

struct bs{
    unsigned a:4;
    unsigned  :4;    /* 空域 */
    unsigned b:4;    /* 从下一单元开始存放 */
    unsigned c:4
}

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

2.位域的宽度不能超过它所依附的数据类型的长度,成员变量都是有类型的,这个类型限制了成员变量的最大长度,: 后面的数字不能超过这个长度。

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

struct k{
    int a:1;
    int  :2;    /* 该 2 位不能使用 */
    int b:3;
    int c:2;
};

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

位域的使用

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

举例:

#include<stdio.h>

int 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;    /* 把位域变量 bit 的地址送给指针变量 pbit */
    pbit->a = 0;    /* 用指针方式给位域 a 重新赋值,赋为 0 */
    pbit->b &= 3;    /* 使用了复合的位运算符 "&=",相当于:pbit->b=pbit->b&3,
                     位域 b 中原有值为 7,与 3 作按位与运算的结果为 3
                     (111&011=011,十进制值为 3) */
    pbit->c |= 1;    /* 使用了复合位运算符"|=",
                     相当于:pbit->c=pbit->c|1,其结果为 15 */
    printf("%d,%d,%d\n", pbit->a, pbit->b, pbit->c);    /* 用指针方式
                                                        输出了这三个域的值 */
}

结果:

1,7,15
0,3,15

typedef

C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字。

按照惯例,定义时会大写字母,以便提醒用户类型名称是一个象征性的缩写,但您也可以使用小写字母。

举例:

typedef unsigned char BYTE;

在这个类型定义之后,标识符 BYTE 可作为类型 unsigned char 的缩写,

BYTE  b1, b2;

unsigned char b1, b2;

您也可以使用 typedef 来为用户自定义的数据类型取一个新的名字。

举例:

#include <stdio.h>
#include <string.h>

typedef struct Books
{
	char  title[50];
	char  author[50];
	char  subject[100];
	int   book_id;
} Book;

int main()
{
	Book book;

	strcpy_s(book.title, 50, "C 教程");
	strcpy_s(book.author, 50, "Runoob");
	strcpy_s(book.subject, 100, "编程语言");
	book.book_id = 12345;

	printf("书标题 : %s\n", book.title);
	printf("书作者 : %s\n", book.author);
	printf("书类目 : %s\n", book.subject);
	printf("书 ID : %d\n", book.book_id);

	return 0;
}

结果:

书标题 : C 教程
书作者 : Runoob
书类目 : 编程语言
书 ID : 12345

typedef vs #define

#define 是 C 指令,用于为各种数据类型定义别名,与 typedef 类似,但是它们有以下几点不同:

  • typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。
  • typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。

强制类型转换

(type_name) expression

类型转换可以是隐式的,由编译器自动执行,也可以是显式的,通过使用强制类型转换运算符来指定。在编程时,有需要类型转换的时候都用上强制类型转换运算符,是一种良好的编程习惯。 

整数提升

整数提升是指把小于 int 或 unsigned int 的整数类型转换为 int 或 unsigned int 的过程。

常用的算术转换

常用的算术转换是隐式地把值强制转换为相同的类型。编译器首先执行整数提升,如果操作数类型不同,则它们会被转换为下列层次中出现的最高层次的类型:

常用的算术转换不适用于赋值运算符、逻辑运算符 && 和 ||。 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C语言中的共用体(Union)和位域(Bit-Field)是用来优化内存使用和灵活操作数据的工具。 共用体是一种特殊的数据类型,它允许不同的变量共享同一块内存空间。共用体中的成员变量共享同一内存,占用内存大小等于最大成员的大小。通过修改共用体的一个成员变量的值,可以影响到其他成员变量的值。共用体适用于在不同的数据类型之间进行转换或者存储占用内存大小不定的数据。 位域是一种特殊的结构体成员变量,可以指定成员变量占用的数,从而实现对内存空间的灵活利用。位域的成员变量必须是整型数据类型,并且位域的大小不能超过该整型类型的大小。位域可以用于减小数据结构占用的内存大小,以及进行数据的操作。 共用体和位域结构体可以一起使用。通过在位域结构体中定义共用体成员变量,可以实现对内存的灵活使用和数据的高效操作。共用体可以用于存储不同类型的数据,而位域可以用于压缩数据的存储空间。这种结合使用的方式可以为我们的程序带来更加高效和节省内存的特点。 总结起来,C语言中的共用体和位域结构体提供了一种优化内存使用和操作数据的方式。它们可以灵活地对内存空间进行利用,并且能够高效地操作数据。通过合理的使用共用体和位域结构体,我们可以达到节省内存和提高程序执行效率的目的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岳小诺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值