【C语言】一篇让你彻底吃透(结构体与结构体位段)(下)

简介: 【C语言】一篇让你彻底吃透(结构体与结构体位段)(下)
  • 练习 3(sizeof(struct S3)输出结果是什么)


struct S3
{
 double d;
 char c;
 int i;
};
printf("%d\n", sizeof(struct S3));


答案是->16

  • 练习4-结构体嵌套问题,以下输出的是什么


struct S3
{
  int d;
  char c;
  int i;
};
struct S4
{
  char c1;
  struct S3 s3;
  int d;
};
printf("%d\n", sizeof(struct S4));


答案是20


为什么存在内存对齐?


大部分的参考资料都是如是说的:


1.平台原因(移植原因):

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2.性能原因

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。


总体来说:

结构体的内存对齐是拿空间来换取时间的做法。


那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:


让占用空间小的成员尽量集中在一起。


//例如:
struct S1
{
  char c1;
  int i;
  char c2;
};
struct S2
{
  char c1;
  char c2;
  int i;
};


S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别。

s1 内存是12个字节

s2 内存是8个字节


结构体传参


struct S
{
  int data[1000];
  int num;
};
struct S s = { {1,2,3,4}, 1000 };
//结构体传参
void print1(struct S s)
{
  printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
  printf("%d\n", ps->num);
}
int main()
{
  print1(s);   //传结构体
  print2(&s); //传地址
  return 0;
}


上面的 print1 和 print2 函数哪个好些?


答案是:首选print2函数。

函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。

如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降


结论:

结构体传参的时候,要传结构体的地址。


位段



结构体讲完就得讲讲结构体实现 位段 的能力。


什么是位段


有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。为了充分利用好内存空间,C语言又提供了一种叫做位段的数据结构


位段能够减少储存数据的位数

信息的存取一般以字节为单位


位段的声明和结构是类似的,有两个不同:

  1. 位段的成员必须是 int、unsigned int 或signed int 。
  2. 位段的成员名后边有一个冒号和一个数字。
  3. : 后面的数字用来限定成员变量占用的位数
  4. 在结构体定义时,指定某个成员变量所占用的是二进制位数(Bit)


例如:


struct A
{
  int _a:2;
  int _b:5;
  int _c:10;
  int _d:30;
};


他们虽然是int类型,在内存占32个比特位,但是 位段限制了他们所占的空间,比如a只能占2个bit,b占5个bit,c占10个bit位,d占10个bit位。

A就是一个位段类型。

那位段A的大小是多少?


  • printf("%d\n", sizeof(struct A));
  • 答案是->8 ,为什么呢?那就关于位段的内存分配了。s


位段的内存分配

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;
};
int main()
{
  struct S s = { 0 };
  s.a = 10;
  s.b = 12;
  s.c = 3;
  s.d = 4;
  system("pause");
}


改代码内存空间是如何开辟的!?图解:


总结:

  1. vs 分配到的内存中的比特位是由右向左使用
  2. 分配的内存剩余的比特位不够使用时,浪费掉


位段的跨平台问题


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

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

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

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


总结:

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


目录
相关文章
|
3月前
|
C语言
【C语言基础篇】结构控制(中)循环结构
【C语言基础篇】结构控制(中)循环结构
|
20天前
|
存储 编译器 程序员
C语言程序的基本结构
C语言程序的基本结构包括:1)预处理指令,如 `#include` 和 `#define`;2)主函数 `main()`,程序从这里开始执行;3)函数声明与定义,执行特定任务的代码块;4)变量声明与初始化,用于存储数据;5)语句和表达式,构成程序基本执行单位;6)注释,解释代码功能。示例代码展示了这些组成部分的应用。
30 10
|
19天前
|
C语言
C语言程序设计核心详解 第四章&&第五章 选择结构程序设计&&循环结构程序设计
本章节介绍了C语言中的选择结构,包括关系表达式、逻辑表达式及其运算符的优先级,并通过示例详细解释了 `if` 语句的不同形式和 `switch` 语句的使用方法。此外,还概述了循环结构,包括 `while`、`do-while` 和 `for` 循环,并解释了 `break` 和 `continue` 控制语句的功能。最后,提供了两道例题以加深理解。
|
19天前
|
存储 算法 C语言
数据结构基础详解(C语言): 二叉树的遍历_线索二叉树_树的存储结构_树与森林详解
本文从二叉树遍历入手,详细介绍了先序、中序和后序遍历方法,并探讨了如何构建二叉树及线索二叉树的概念。接着,文章讲解了树和森林的存储结构,特别是如何将树与森林转换为二叉树形式,以便利用二叉树的遍历方法。最后,讨论了树和森林的遍历算法,包括先根、后根和层次遍历。通过这些内容,读者可以全面了解二叉树及其相关概念。
|
19天前
|
C语言
C语言程序设计核心详解 第三章:顺序结构,printf(),scanf()详解
本章介绍顺序结构的基本框架及C语言的标准输入输出。程序从`main()`开始依次执行,框架包括输入、计算和输出三部分。重点讲解了`printf()`与`scanf()`函数:`printf()`用于格式化输出,支持多种占位符;`scanf()`用于格式化输入,需注意普通字符与占位符的区别。此外还介绍了`putchar()`和`getchar()`函数,分别用于输出和接收单个字符。
|
19天前
|
存储 机器学习/深度学习 C语言
数据结构基础详解(C语言): 树与二叉树的基本类型与存储结构详解
本文介绍了树和二叉树的基本概念及性质。树是由节点组成的层次结构,其中节点的度为其分支数量,树的度为树中最大节点度数。二叉树是一种特殊的树,其节点最多有两个子节点,具有多种性质,如叶子节点数与度为2的节点数之间的关系。此外,还介绍了二叉树的不同形态,包括满二叉树、完全二叉树、二叉排序树和平衡二叉树,并探讨了二叉树的顺序存储和链式存储结构。
|
19天前
|
存储 C语言
C语言程序设计核心详解 第九章 结构体与链表概要详解
本文档详细介绍了C语言中的结构体与链表。首先,讲解了结构体的定义、初始化及使用方法,并演示了如何通过不同方式定义结构体变量。接着,介绍了指向结构体的指针及其应用,包括结构体变量和结构体数组的指针操作。随后,概述了链表的概念与定义,解释了链表的基本操作如动态分配、插入和删除。最后,简述了共用体类型及其变量定义与引用方法。通过本文档,读者可以全面了解结构体与链表的基础知识及实际应用技巧。
|
24天前
|
C语言
c语言中的结构体
本文档详细介绍了C语言中结构体的使用方法,包括结构体的基本定义、变量声明与赋值、数组与指针的应用,以及结构体嵌套、与`typedef`结合使用等内容。通过示例代码展示了如何操作结构体成员,并解释了内存对齐的概念。
|
1月前
|
C语言
C语言------选择结构
这篇文章是C语言选择结构的入门实训,包括多个练习题及其源代码,旨在帮助读者熟练掌握条件语句和选择结构程序设计方法,并熟悉switch语句和程序调试过程。
C语言------选择结构
|
30天前
|
C语言
C语言结构体赋值的四种方式
本文总结了C语言结构体的四种赋值方式,并通过示例代码和编译运行结果展示了每种方式的特点和效果。
46 6