C语言结构体详解(下)

简介: C语言结构体详解(下)

1.结构体声明

1.1结构体类型

这里我们定义一个结构体:

struct Stu
{
  char name[20];
  int age;
};

struct Stu就是结构体类型

1.1.1匿名结构体类型

//匿名结构体类型
struct
{
  int a;
  char b;
  float c;
}s;
struct
{
  int a;
  char b;
  float c;
}*ps;

这里的struct在声明的时候省略掉了结构体标签,这里的s,*ps是结构体变量名,像这样的省略标签项的结构体类型就是匿名结构体

这里有一个疑问,如果令 ps=&s 可以吗?答案是不行的,它们虽然成员相同,不过并不是同一个结构体,存放在不同的内存空间,编译器会把上面的两个声明当成完全不同的两个类型,是非法的

1.1.2 typedef定义结构体类型

代码运用:

typedef struct Stu
{
  int a;
  char b;
  float c;
}Node;
int main()
{
  Node n={1,'w',5.24};
  printf("%d %c %lf", n.a, n.b, n.c);//1 w 5.240000
  return 0;
}

当结构体类型比较复杂时就可以用typedef将结构体类型重定义,如上面的代码中将struct Stu重定义为Node后再使用

1.2结构体自引用

在结构中可以包含一个类型为该结构本身的成员,如:

struct Stu
{
  char name[20];
  int age;
  struct Stu* date;//OK
  //struct Stu date;//err
  //Stu date;//err
};

注意:结构体自引用只能使用传址调用,传值调用(sizeof(struct Stu)无法得知结构体大小)或者是省略结构体关键字都是错误的写法

1.3结构体内存对齐

结构体内存对齐主要用于帮助我们计算结构体的大小。

结构体的对齐规则:

1.结构体的第一个成员直接对齐到相对于结构体变量起始位置为0的地址处

2.从第二个成员开始,要对齐到某个数字(对齐数)的整数倍的偏移处

对齐数:结构体成员自身大小和编译器默认对齐数的较小值

VS中默认对齐数为8

Linux环境默认不设对齐数(对齐数是结构体成员的自身大小)

3.结构体的总大小必须是最大对齐数的整数倍。

每个结构体成员都有一个对齐数,其中最大的对齐数就是最大对齐数

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

1.3.1结构体大小计算实例

例题一

struct S1
{
  char c1;
  int i;
  char c2;
};
int main()
{
  printf("%d\n", sizeof(struct S1));
  return 0;
}
//输出12

题解:

915796df5d70c799e03c82365fcb3e5f.png

例题二

struct S2
{
  char c1;
  char c2;
  int i;
};
int main()
{
  printf("%d\n", sizeof(struct S2));
  return 0;
}
//输出8

题解:

3a3989893a94417481bb93f40f469123.png

例题三

struct S1
{
  char c1;
  int i;
  char c2;
};
struct S2
{
  char c3;
  struct S1 s;
  double d;
};
int main()
{
  printf("%d\n", sizeof(struct S4));
  return 0;
}
//输出32

题解:

463ef1dbf94b4e46f54b0873057204d5.png

1.3.1为什么存在内存对齐

  1. 平台原因(移植原因):
  2. 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  3. 性能原因:
  4. 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
  5. 总体来说:结构体的内存对齐是拿空间来换取时间的做法。
  6. 在设计结构体的时候,我们既要满足对齐,又要节省空间,就要做到,让占用空间小的成员尽量集中在一起。如上述的例题一和例题二。

1.4修改默认对齐数

可以使用#prangma预处理指令改变我们的默认对齐数。结构在对齐方式不合适的时候,我们可以自己更改默认对齐数。

代码实例:

#include <stdio.h>
#pragma pack(1)//设置默认对齐数为8
struct S1
{
  char c1;
  int i;
  char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
struct S2
{
  char c1;
  int i;
  char c2;
};
int main()
{
  printf("%d\n", sizeof(struct S1));//输出6
  printf("%d\n", sizeof(struct S2));//输出12
  return 0;
}

2.位段

2.1什么是位段?

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

1.位段的成员必须是 int、unsigned int 或signed int 。

2.位段的成员名后边有一个冒号和一个数字。

3.位段-这里的位是二进制位

代码实例:

struct Stu
{
  int a : 2;
  int b : 5;
  int c : 10;
  int d : 30;
};

2.2位段的内存分配

  1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
  2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
  3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
  4. 代码实例:
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;
  printf("%d\n", sizeof(struct S));//输出3
  return 0;
}

图解:

3da306bbace72984f248ab7e8bc75692.png

2.3位段的跨平台问题

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

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

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

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

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

好了今天的内容就到这里了,对友友们有帮助的话不妨来个三连加关注支持一下,后期后持续更新C语言干货!

目录
相关文章
|
8天前
|
存储 C语言
C语言程序设计核心详解 第九章 结构体与链表概要详解
本文档详细介绍了C语言中的结构体与链表。首先,讲解了结构体的定义、初始化及使用方法,并演示了如何通过不同方式定义结构体变量。接着,介绍了指向结构体的指针及其应用,包括结构体变量和结构体数组的指针操作。随后,概述了链表的概念与定义,解释了链表的基本操作如动态分配、插入和删除。最后,简述了共用体类型及其变量定义与引用方法。通过本文档,读者可以全面了解结构体与链表的基础知识及实际应用技巧。
|
13天前
|
C语言
c语言中的结构体
本文档详细介绍了C语言中结构体的使用方法,包括结构体的基本定义、变量声明与赋值、数组与指针的应用,以及结构体嵌套、与`typedef`结合使用等内容。通过示例代码展示了如何操作结构体成员,并解释了内存对齐的概念。
|
19天前
|
C语言
C语言结构体赋值的四种方式
本文总结了C语言结构体的四种赋值方式,并通过示例代码和编译运行结果展示了每种方式的特点和效果。
27 6
|
29天前
|
编译器 程序员 Linux
【C语言篇】结构体和位段详细介绍
跟结构相⽐,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。
|
1月前
|
存储 C语言
C语言------结构体和共用体
这篇文章是关于C语言中结构体和共用体的实训,通过示例代码演示了结构体的定义、赋值、使用,以及如何使用结构体变量进行数据的组织和操作,包括输入、排序、求平均分和查找学生信息等功能。
C语言------结构体和共用体
|
3月前
|
编译器 测试技术 C语言
【C语言】:自定义类型:结构体的使用及其内存对齐
【C语言】:自定义类型:结构体的使用及其内存对齐
50 7
|
3月前
|
网络协议 编译器 Linux
结构体(C语言)
结构体(C语言)
|
3月前
|
算法 Java 程序员
面向对象编程(OOP)通过对象组合构建软件,C语言虽是过程式语言,但可通过结构体、函数指针模拟OOP特性
【6月更文挑战第15天】面向对象编程(OOP)通过对象组合构建软件,C语言虽是过程式语言,但可通过结构体、函数指针模拟OOP特性。封装可使用结构体封装数据和方法,如模拟矩形对象。继承则通过结构体嵌套实现静态继承。多态可通过函数指针模拟,但C不支持虚函数表,实现复杂。C语言能体现OOP思想,但不如C++、Java等语言原生支持。
49 7
|
3月前
|
编译器 C语言
【C语言基础】:自定义类型(一)--> 结构体-2
【C语言基础】:自定义类型(一)--> 结构体
|
3月前
|
编译器 Linux C语言
【C语言基础】:自定义类型(一)--> 结构体-1
【C语言基础】:自定义类型(一)--> 结构体