c语言回顾-结构体(2)(下)

简介: c语言回顾-结构体(2)(下)

c语言回顾-结构体(2)(上):https://developer.aliyun.com/article/1624398


位段式结构中的位可以理解二进制位

在C语言中,位段的大小取决于编译器和硬件平台的具体实现。通常,位段的大小是按照字节对齐的,但是位段内部的位数是按照定义的位数来分配的。

上述位段占了47位,对齐6个字节,也就是48位,但是用sizeof测试时出来是8字节

在大多数系统中,位段会按照最接近的字节边界对齐。由于这个结构体总共占用了47位,它可能会被对齐到6个字节(48位),因为这是最接近47位的字节数,并且可以容纳所有的位段。

然而,位段的确切大小和对齐方式取决于编译器和硬件平台的具体实现。在某些系统上,如果位段不能恰好填充到一个字节,编译器可能会分配额外的位来填充到下一个字节边界。此外,如果位段的大小超过了单个整数类型(通常是32位或64位)的位数,编译器可能会将它们分割到多个整数中。

3.2位段的内存分配

1. 位段的成员可以是 int unsigned int signed int 或者是 char 等类型

2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。

3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。


struct S
{
 char a:3;
 char b:4;
 char c:5;
 char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

接下来通过画图来看内存空间的开辟分配

1.在申请的一块内存中,bit位是从左到右,还是从右到左使用,是不确定的,VS是从右到左

2.剩余的空间,不足下一个成员使用的时候,是浪费?还是继续使用?VS采取浪费

ok,回到最上面那个位段求大小

struct A

{

int _a:2;//占2个两个bit位

int _b:5;

int _c:10;

int _d:30;

};

一次性申请4个字节,第一次用17个bit位,剩余15个不够用,根据VS的规则,采取浪费,所以再次申请4个字节存取剩下的_d数据。

即该位段大小为8

3.3位段的跨平台问题

1. int 位段被当成有符号数还是无符号数是不确定的。

2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。

eg:32位或者64位int的长度占4个字节,16位int是2个字节

3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。

4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。

总结:

跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。

所以需要根据不同的平台写不同的代码。

3.4位段的应用

IP数据报的格式,我们可以看到其中很多的属性只需要几个bit位就能描述,这里使用位段,能够实现想要的效果,也节省了空间,这样网络传输的数据报大小也会较小一些,对网络的畅通是有帮助的。

3.5位段使用的注意事项

位段的几个成员共有同一个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位 置处是没有地址的。内存中每个字节分配一个地址,一个字节内部的bit位是没有地址的。

所以不能对位段的成员使用&操作符,这样就不能使用scanf直接给位段的成员输入值,只能是先输入放在一个变量中,然后赋值给位段的成员。


struct A {
  int _a : 2;
  int _b : 5;
  int _c : 10;
  int _d : 30;
};
int main() {
   struct A sa = {0};
   scanf("%d", &sa._b);//这是错误的
//正确的⽰范
   int b = 0;
   scanf("%d", &b);
   sa._b = b;
   return 0;
}

下面是搜集的位段注意事项的其他总结

1. 可移植性问题:位段的行为和大小可能因编译器和硬件平台而异。因此,位段不具有可移植性,应该避免在需要跨平台兼容的代码中使用位段。

2. 对齐和大小:位段的对齐方式和大小取决于编译器的实现。编译器可能会将位段对齐到字节边界,这可能导致额外的填充位。因此,不应该假设位段的确切大小,除非编译器文档明确说明了位段的行为。

3. 位段类型:位段通常使用 `unsigned int` 或 `int` 类型定义,但编译器可能会允许其他整数类型。然而,使用非标准类型可能会降低代码的可移植性。

4. 位段操作:位段的操作不如普通变量直观,因为它们涉及到位的操作。在访问和修改位段时,需要小心处理位操作,以避免错误。

5. 位段顺序:位段在内存中的存储顺序可能因编译器而异。有些编译器可能按照位段的定义顺序存储,而其他编译器可能按照相反的顺序存储。

6. 位段跨越字节边界:如果一个位段的大小超过了单个字节的位数,它将会被分割到两个字节中。这可能会导致难以预测的内存布局。

7. 位段的符号性:如果使用 `int` 类型定义位段,位段可能是带符号的。这意味着位段的最高位可能被解释为符号位,这可能会导致意外的行为。为了确保位段是无符号的,应该使用 `unsigned int` 类型。

8. 位段的访问:在某些平台上,访问位段可能比访问普通变量更慢,因为位段需要额外的位操作。

9. 位段的初始化和赋值:位段的初始化和赋值可能需要特殊的位操作,因为它们不是以字节为单位进行操作的。

10. 位段的限制:位段不能用于数组或指针,也不能用于结构体或联合体的嵌套定义。

在使用位段时,应该仔细考虑这些注意事项,并确保代码的可读性、可维护性和正确性。如果可能,应该考虑使用其他技术,如位掩码或位操作函数,来代替位段,以提高代码的可移植性和可读性。

OK,本节内容到此结束,支持小编的留下你的关注,评论和点赞吧!!!

目录
相关文章
|
4天前
|
C语言
C语言结构体链式结构之有头单链表
文章提供了一个C语言实现的有头单链表的完整代码,包括创建链表、插入、删除和打印等基本操作。
13 1
|
8天前
|
C语言
初识C语言6——结构体
初识C语言6——结构体
14 3
|
10天前
|
存储 编译器 C语言
【C语言】探索结构体基础知识:简明概要
【C语言】探索结构体基础知识:简明概要
|
2天前
|
存储 编译器 Linux
深入C语言:探索结构体的奥秘
深入C语言:探索结构体的奥秘
|
2天前
|
存储 编译器 程序员
c语言回顾-结构体(2)(上)
c语言回顾-结构体(2)(上)
16 0
|
2天前
|
存储 C语言
c语言回顾-结构体
c语言回顾-结构体
6 0
|
8天前
|
存储 编译器 Linux
深入理解C语言中的结构体
深入理解C语言中的结构体
|
1月前
|
存储 C语言
C语言程序设计核心详解 第九章 结构体与链表概要详解
本文档详细介绍了C语言中的结构体与链表。首先,讲解了结构体的定义、初始化及使用方法,并演示了如何通过不同方式定义结构体变量。接着,介绍了指向结构体的指针及其应用,包括结构体变量和结构体数组的指针操作。随后,概述了链表的概念与定义,解释了链表的基本操作如动态分配、插入和删除。最后,简述了共用体类型及其变量定义与引用方法。通过本文档,读者可以全面了解结构体与链表的基础知识及实际应用技巧。
|
1月前
|
C语言
c语言中的结构体
本文档详细介绍了C语言中结构体的使用方法,包括结构体的基本定义、变量声明与赋值、数组与指针的应用,以及结构体嵌套、与`typedef`结合使用等内容。通过示例代码展示了如何操作结构体成员,并解释了内存对齐的概念。
|
2月前
|
C语言
C语言结构体赋值的四种方式
本文总结了C语言结构体的四种赋值方式,并通过示例代码和编译运行结果展示了每种方式的特点和效果。
111 6