c语言中的结构体和字节对齐

结构体

结构体的概念

★ 计算机程序设计语言都有数据类型的概念

★ 数据类型一般有基本类型和用户自定义类型

★ c语言中,基本类型有int型、double型、char型等等。

★ 而结构体类型则属于用户自定义类型,是由基本类型组合而成的复杂类型。

★ 定义好的结构体类型可以像基本类型一样去定义此类型的变量。

定义结构体类型和定义结构体类型变量

★ 我们先看看定义结构体类型的一般形式:

struct 结构体标示符

{

    结构体元素;

}

如下:

struct StructDemo

{

    char c;

    int  i;

};

★ 定义结构体类型变量方式一:

定义类型的同时定义变量,如下:

struct StructDemo

{

    char c;

    int  i;

}sd1,sd2;

这样就定了两个结构体变量sd1,sd2了,这两个变量的类型是struct StructDemo类型。

★ 定义结构体类型变量方式二:

定义类型之后定义变量,如下:

struct StructDemo

{

    char c;

    int  i;

};

这个定义说明我们已经定义完成了一个新的类型,这个类型说明符就是struct StructDemo

所以我们可以用此来定义变量了。如下:

struct StructDemo sd1,sd2;

★ 定义结构体类型变量方式三:

类型说明符重命名的方法。

学习C语言的朋友,对typedef估计不会陌生的,用它可以给类型说明符一个别名,此名字和原来的名字具有同样意义。

如:typedef int zhengxing;

那么int izhengxing i是一样的意思。

同样的道理也可运用于我们自定义的数据类型。

typedef struct StructDemo  SD;

SD sd1,sd2;

结构体类型的初始化

★ 定义的同时初始化,如:

   struct StructDemo sd1 = {A,10},sd2 = {B,12};

SD sd1 = {A,10},sd2 = {B,12};

struct StructDemo

{

    char c;

    int  i;

} sd1 = {A,10},sd2 = {B,12};

★ 定义之后再初始化,如:

sd1 = {A,10};

sd2 = {B,12};

sd1.c = D;

sd1.i = 20;

结构体运用举例1

我们将上面所说的结构体的定义、定义结构体类型变量、初始化用一个实际的程序来呈现,我现在这台机器上装的linux系统是OpenSuSe,所以我们打开OpenSuSe,打开终端,利用vim编辑程序StructDemo01.c如下:

 

 

编译运行如下:

 

 

结构体的大小问题

    计算机程序语言中的数据类型在使用时在计算机中都会占有一定的内存空间,结构体类型是用户自定义类型,也属于数据类型的一种,那么它在计算机内存中占有的空间大小又是什么情况呢?下面我们来看一下。

我们定义一个结构体类型如下:

Struct StuctDemo

{

   char c;

   int i;

};

我们先尝试估计一下这个结构体类型所占有的内存空间的大小,我们知道一个char类型占有1个字节,而一个int类型占有4个字节,那么我们是否可以认为这个结构体类型占有的内存空间为5个字节呢?

下面我们用程序来验证这个问题,这也是我们学习计算机所有的常用手法,快捷方便准确。

在举例子之前我们说一下一个关键字sizeofsizeof可以告诉我们一个数据类型占有的内存空间到底有多大,具体形式:sizeof(类型说明符)得到字节数。

下面我们创建一个c语言源程序文件命名为Demo02.c,我们用vim打开编辑如下:

 

 

我们编译运行:

 

 

结果大出我们所料,结果竟然是8,为什么不是5呢?

现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。

  其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则:   1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;   2) 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;例如上面第二个结构体变量的地址空间。   3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

看了这段文字相信我们很容易理解为什么是8而不是5了,正是因为字节对齐的需要。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章