结构体知识的总结

结构体类型创建
结构体初始化
结构体内存对齐
位段,位段计算机大小。
枚举+联合。

在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类。结构体可以被声明为变量、指针或数组等,用以实现较复杂的数据结构。结构体同时也是一些元素的集合,这些元素称为结构体的成员(member),且这些成员可以为不同的类型,成员一般用名字访问。
下面是关于结构体的一些理解
关于结构体类型的创建
先来看看下面的例子

struct Pro//Pro为标签字段为成员列表提供一个名字
{
	int amount;
	int price;
};
//声明Pro类型的结构体

这个声明把Pro和这个成员列表联系到一起,但并没有提供变量列表,所以它没有创建任何变量。标签标识了一种模式,用于声明未来的变量。

struct Pro x;//创建变量

声明结构体可以使用typedef来创建一个新类型,它和声明结构标签效果几乎相同,区别在于Pro现在是一个类型名,而并不是标签。

typedef struct
{ 
        int a;
        int b;
}Pro;
Pro x;//创建一个Pro类型的变量x

关于结构体的自引用,先举一个正确的例子

//结构体自引用
struct Node
{
 int data;
 struct Node *b;
};

声明中b是一个指针而不是结构,编译器在结构长度确定之前就已经知道指针的长度。因此这样的声明是合法的。

struct Node
{
      int a;
      struct Node b;
};

这样的自引用是非法的,因为成员b是另一个完整的结构,其内部还包含自己的成员b,第二个成员如此重复下去无法终止。还有一种写法是值得警惕的,例如下面所举的例子。

typedef struct
{
      int a;
      Pro *b;
}Pro;

虽然上述例子中b是一个指针,但是由于类型名直到声明的末尾才定义。在结构体内部还尚未定义。因此是错误的。
结构体的初始化
结构体的初始化还是比较简单的,用一对花括号,其内部用逗号分隔开各个成员的初始化,这些值根据成员列表按顺序写出。

struct Pro
{
      int a;
      int b[5];
}x={
      10,
      {1,2,3,4};
};

结构体的内存对齐
在这里插入图片描述
上述代码,根据我们我们平常所说其结构体大小为六,但在调整了char 和int的位置后,结果不尽相同。这是因为存在内存对齐这一点。
首先我们需要了解对齐规则:
1、第一个成员在与结构体变量偏移量为0的地址处。
2、每个成员,要放在对齐数的整数倍的地址处。
对齐数:每个成员自己的大小和编译器默认的对齐数进行比较取最小值
3、结构体大小=结构体每个成员的最大对齐数的整数倍(靠最近的)
如上图所示。
对于内存对齐,主要是为了提高程序的性能,数据结构,特别是栈,应尽可能在自然边界上对齐,经过对齐后,cpu的内存访问速度大大提升。
1、平台原因(移植原因)(百度查询所得)
(1) 不是所有的硬件平台都能访问任意地址上的任意数据的;
(2) 某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:
(1)数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
(2) 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
简而言之,就是利用空间的浪费,来换取时间。
根据上面例子,我们发现第二种结构只占用了8个字节的空间,相比于第一个,节省了一点空间。为了减少内存对齐所带来的的空间损失。我们可以尽可能的把相关的结构成员存储在一起。以提高程序的可维护性和可读性。但如果不存在,结构的成员应该根据他们的边界需要重排,从而减少边界对齐造成的内存损失。那么使用pragma pack显得重要了
在这里插入图片描述
pragma pack用于调整内存对齐字节数。
位段
位段和结构体相似,但存在两个不同
1.位段的成员必须是 int、unsigned int 或signed int 。
2.位段的成员名后边有一个冒号和一个数字。

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

(1) 位段的内存分配

  1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
  2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
  3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
    (2)位段的跨平台问题
  4. int 位段被当成有符号数还是无符号数是不确定的。
  5. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。
  6. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  7. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位
    还是利用,这是不确定的。
    (3)总结:
    跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。

枚举与联合
(1)枚举

enum Day
{
     Mon,
     Tues,
     Wed,
     Thur,
     Fri,
     Sat,
     Sun
};

枚举默认值为0,依次递增。关于枚举的优点,有以下几点

  1. 增加代码的可读性和可维护性
  2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
  3. 防止了命名污染(封装)
  4. 便于调试
  5. 使用方便,一次可以定义多个常量
    (2)联合类型的定义
    联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以
    联合也叫共用体)。 比如:
union Un //联合类型的声明
{ 
 char c; 
 int i; 
}; 
//联合变量的定义
union Un un; 
//计算连个变量的大小
printf("%d\n", sizeof(un)); 

根据《C和指针参考所得》。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值