首先来简单介绍一下结构体。结构体是一些值的集合,这些值成为它的成员。结构体的每个成员可能具有不同的类型,且都有自己的名字。所以结构体的成员由两部分构成,类型和名字。结构体创建的变量交结构变量,结构变量属于标量类型,可像对待其他标量类型那样执行相同类型的操作。
下边看一个例子来帮助理解这些概念。
结构体的声明:
结构体在声明的时候必须要列出它包含的所有成员。
看如下两个结构体的声明
上边两种声明都是合法的。第一个结构体声明创建了一个名为x的结构变量,第二个结构体声明创建了一个y和一个z。y是一个包含了20个结构的数组,y的每一个元素都都包含结构体的这三个成员。而z是一个指针,它指向这个类型的结构。
虽然两个结构体的成员都相同,但是他们仍是两个不同的结构体,所以 z=&x 是非法的。
结构体可以在声明的同时定义变量,也可以先声明,在要用的时候再定义变量。定义的格式为struct 结构体名 变量名(struct Simple x)
再看下边这个例子
结构体的标签声明:
此时 z=&x 是合法的。
结构体的typedef声明
注:如果想在多个源文件中使用同一种类型的结构体,应该吧标签声明或typedef的声明放在一个头文件中,当源文件需要这个声明是用#include 指令吧那个头文件包含进来就行了。
结构体的访问:
直接访问:通过点操作符(.)访问。访问格式为:结构体变量 . 需访问成员名(Stu . name)。
间接访问:通过指向操作符(—>)访问。
p—>a 该式子可实现对成员a的访问。
结构体的初始化:
结构体是不能在声明的时候初始化的。
结构体是用一个位于花括号内部,由逗号分隔的初始值列表进行初始化
举个例子
结构的存储分配:
看如下例子:
#include <stdio.h>
#include <stdio.h>
struct LINE
{
char a;
int b;
float c;
};
int main()
{
printf("%d",sizeof(struct LINE));
return 0;
}
它的最后结果会是什么呢?
会是几个成员类型大小的总和9么?来看一看程序的结果
可以看到并不是9,而是12.(可以自己去验证一下)
这是由于什么原因造成的呢,这就要提到内存对齐了。
首先来说一下内存对齐的3条规则(要牢记):
1、结构的第一个成员永远都放在结构的0偏移处。
偏移就是往后挪,n偏移就是从系统默认开始分配内存的地方往后挪n个字节,0偏移就是挪0个,也就是相当于没有挪。
2、从第二个成员开始,都要对齐到某个对齐数的整数倍处。
对齐数:结构体成员自身大小和默认对齐数的较小值。
默认对齐数:VS-----8 linux-----4
3、结构体的总大小必须是最大对齐数的整数倍。
系统的默认对齐数是可以改的,使用#pragma pack( )设置默认对齐数
查看结构体中某个成员相对于结构体起始位置的偏移量
offsetof(A,a) A是一个结构体变量,a是A的一个成员
4、如果结构体里边嵌套有一个结构体,对应的结构体成员要对齐到这个结构体的最大对齐数的整数倍。
现在以上边的例题来详细的讲解一遍
下面再举几个例子再熟悉一下这几条规则:
#include <iostream>
using namespace std;
struct B
{
char d; //占用0偏移 对齐数为1
int e; //占用4-7偏移 对齐数为4
};
struct A
{
int a; //占用0-3偏移 对齐数为4
char c[6]; //占用4-9偏移 对齐数为1
B b; //占用12-19偏移,对齐数是4
//因为B类型的大小为8,对齐数为B的最大对齐数,即4。偏移位置为对齐数的整数倍
};
int main()
{
cout << "size of A: " << sizeof(A) << endl;
cout << "size of B: " << sizeof(B) << endl;
cout << "a:" << offsetof(A, a) << endl;
cout << "c:" << offsetof(A, c) << endl;
cout << "b:" << offsetof(A, b) << endl;
cout << "d:" << offsetof(B, d) << endl;
cout << "e:" << offsetof(B, e) << endl;
return 0;
}
讲了这么多关于内存对齐的规则和运用,那么为什么要内存对齐呢?
现在就来讲一下内存对齐的原因吧。
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处去某些特定类型的数据,否则跑出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要访问一次。