您的位置:首页 > 编程语言 > C语言/C++

浅析C语言结构体及位段

2017-07-08 23:10 274 查看
      数据经常以组的形式存在。例如,学校需要了解每位学生的姓名,学号和成绩等。如果这些值储存在一起,访问起来会更加简单。但如果类型不同,就无法存储于同一个数组中。所以在C语言中可以使用结构把不同类型的值存储在一起。
  先来看看百度百科对结构体的定义:结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,叫做结构。数组是相同类型的元素的集合,结构也是一些值的集合,这些值称为它的成员。
  声明一个结构体类型的形式:
struct Student    //声明一个结构体类型Studet
{
char name[20];//声明一个字符型数组name
char sex[5];     //声明一个字符型数组sex
int age;      //声明一个整形变量age
float score;  //声明一个单精度型变量score
};

在声明结构时,必须离出它包含的所有成员。这个列表包括每个成员的类型和名字。
接下来看看如何定义一个结构体变量:
struct Student    //声明一个结构体类型Studet
{
char name[20];//声明一个字符型数组name
char sex[5];     //声明一个字符型数组sex
int age;      //声明一个整形变量age
float score;  //声明一个单精度型变量score
};int main()
{
struct Student stu1;//这样就定义了一个结构体类型变量stu1
system("pause");
return 0;
}

 也可以在声明类型的时候直接定义变量,如下:
struct Student    //声明一个结构体类型Studet
{
char name[20];//声明一个字符型数组name
char sex[5];     //声明一个字符型数组sex
int age;      //声明一个整形变量age
float score;  //声明一个单精度型变量score
}stu2;
int main()
{
stu2.age;//直接在声明类型的时候定义的变量访问成员
system("pause");
return 0;
}


关于结构体的类型要注意的几点:
(1)类型与变量是不同的概念,不要混淆。只能对结构体变量中的成员赋值,而不能对结构体类型赋值。

(2)对结构体变量中的成员(即“域”),可以单独使用,它的作用与地位相当于同类型的普通变量。

(3)结构体的成员也可以是一个结构体变量。

那么结构体该如何初始化呢?直接上例子:

1.在定义结构体时直接初始化

struct Student{      //声明一个结构体类型Student
char name[20];   //声明一个字符型数组name
char sex[5];        //声明一个字符型数组sex
int age;         //声明一个整形变量age
float score;     //声明一个单精度型变量
} stu1 = {
"zhangsan",
'm',
20,
90,
};


2.在定义变量时进行初始化

struct Student    //声明一个结构体类型Studet
{
char name[20];//声明一个字符型数组name
char sex[5];  //声明一个字符型数组sex
int age;      //声明一个整形变量age
float score;  //声明一个单精度型变量score
};
int main()
{
struct Student stu1 = { "lisi", "男", 19, 100 };
system("pause");
return 0;
}

有的同学可能会觉得每次定义变量的时候都需要写上很长的类型名,为了方便我们可以用typedef关键字,对类型进行重命名,如下:



那么,结构在内存中是如何存储的呢?先来看看我们之前定义好的结构体的大小:




发现是36个字节,这是因为结构体内部存在对齐规则。

1、第一个成员对齐到整个结构的0偏移处

2、从第二个成员开始,每个成员都要对齐到对齐数的整数倍处去

3、整个结构的最终大小必须是所有对齐数中最大对齐数的整数倍

对齐数----成员自身大小和默认对齐数中的较小值

默认对齐数:VS----8字节    Linux----4字节

默认对齐数是可以修改的,利用 #pragma pack(修改后的字节数),就可以对当前平台的对齐数进行修改。

那么,为什么要存在对齐规则呢?我们可以从以下两个方面去解释:

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

2.性能原因:数据结构应该尽可能的在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问,而对齐的内存访问仅需要一次访问。

关于结构,就要说说它实现位段的能力。位段的声明和结构类似,但是它的成员是一个或多个位的字段。这些不同长度的字段实际上存储于一个或多个整型变量中。

位段的声明和任何普通的结构成员声明相同,但是有两个例外。首先,位段成员必须声明为int、signed int或unsigned int类型。其次,在成员名后面是一个冒号和一个整数,这个整数指定该位段所占用的位的数目。

struct node
{
unsigned int a:4; //位段a,占4位
unsigned int :0; //无名位段,占0位
unsigned int b:4; //位段b,占4位
int c:32; //位段c,占32位
int :6; //无名位段,占6位
};

位段在内存中的存储方式:对于位段结构,编译器会自动进行存储空间的优化,主要有这几条原则:

   1)如果一个位段存储单元能够存储得下位段结构中的所有成员,那么位段结构中的所有成员只能放在一个位段存储单元中,不能放在两个位段存储单元中;如果一个位段存储单元不能容纳下位段结构中的所有成员,那么从剩余的位段从下一个位段存储单元开始存放。(在VC中位段存储单元的大小是4字节).

   2)如果一个位段结构中只有一个占有0位的无名位段,则只占1或0字节的空间(C语言中是占0字节,而C++中占1字节);否则其他任何情况下,一个位段结构所占的空间至少是一个位段存储单元的大小;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言