关于结构体,枚举和联合

结构体

定义:结构是一些值的集合,这些值称为结构的成员变量,结构的每个成员可以是不同类型的变量

声明:举例如下
struct Stu                //定义一个结构体类型Stu
{
	char name[20];       // 定义一个成员变量name
	int age;             //定义一个成员变量age
	char sex[5];         //定义一个成员变量sex
};


特殊声明(匿名结构体类型)

struct
{
	int a;
	float b;
	double c;
}x;

对于结构体可以这样理解,struct关键字说明这是一个结构体,结构体类型名限制了结构体变量的范围,就如同int 一般,有人表示了这个变量的范围。

:对于匿名结构体,如果两个匿名结构体的成员是一样的,千万不要以为它们是一个结构体,编译器可不这样认为。

结构体的访问

通过".","->"访问


int main()
{
	struct Stu s;
	struct Stu *p;
	s.age = 20;                      //点运算符的左边操作数是一个结果为结构的表达式
	strcpy(p->name , "zhangsan");    //箭头的左边操作数是一个指向结构体的指针

	return 0;
}

结构体的自引用

在结构体中包含一个类型为该结构本身的成员。(链表的举例)

struct Node
{
	int data;
	struct Node *next;        //指向同类型数据的指针
};

结构体的内存对齐
对于结构体的内存对齐通常解释有以下两个原因

1.平台原因
不是所有的硬件平台都能访问 任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常
2.性能原因
数据结构(尤其是栈)应该尽可能在自然边界上对齐,因为对于没有对齐的内存,处理器需要做两次数据访问,而对于对齐的数据内存,处理器只需要做一次数据访问

结构体对齐原则:
1.第一个成员在于结构体变量偏移量为0的地址处
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处,对齐数为编译器默认的对齐数与该成员大小的较小值
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
4.如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

举个栗子:

struct S3            //16
{ 
	double d;  
	char c;   
	int i; 
}; 

 struct S4          //32
 {    
	 char c1;
	 struct S3 s3;   
	 double d;
 };

对于第一个结构体而言,根据上述规则,大小为 8+1+3+4 = 16
对于第二个结构体而言,也根据上述规则,可以得到 1+7+16+8 = 32

从上面的两个例子我们可以看到都存在内存浪费的问题,那么,怎么让内存见谅不会被浪费呢?答案是,让占用空间小的成员尽量集中在一起。

结构体传参
结构体传参的时候尽量传入地址,因为函数传参的时候,参数是需要压栈的,如果所传入的结构体过大,参数压栈的系统开销比较大,会导致性能的下降

举例如下:

struct S3            
{ 
	double d;  
	char c;   
	int i; 
}; 

void print(struct S3 *ps)
{
	printf("%c\n", ps->c);
}
int main()
{
	struct S3 s3 = { 0.0, 'a', 2 };
	print(&s3);
	return 0;
}

位段

1.位段的成员必须是int, unsigned int,signed int.
2.位段的成员名有一个冒号和一个数字

比如下面的例子:
struct A
{ 
	int _a : 2; 
	int _b : 5;   
	int _c : 10;    
	int _d : 30;
};

位段的内存分配
1.位段的的成员可以是int ,unsigned int ,signed int 或者是char (属于整型家族)类型
2.位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的
3.位段是涉及很多不确定的因素,位段是不跨平台的,注重可移植的程序应该避免使用位段

下面的例子又是怎么样开辟空间的

struct S 
{
	char a : 3;  
	char b : 4;   
	char c : 5;
	char d : 4;
};

struct S s = { 0 }; 
s.a = 10;
s.b = 12; s.c = 3;
s.d = 4;

分析一下可得总共需要开辟三个字节的空间。

枚举

enum Sex
{
	MALE,
	FEMALE,
	SECERET
};                   //可以直接在大括号外面写变量名称,但是这样创建的是全局的变量,所以不太使用

联合体

联合体的成员是共用一块内存空间的,共用的是对应字节的空间,其中一个改变影响另外一个成员
联合体大小的计算

1.联合体的大小最少是最大成员的大小
2.当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
union ip_addr
{
	unsigned long addr;  
	//四个字节的内容要一个一个字节的拿出来,而如果直接后面写4个char类型的,只是拿到了第一个。
	struct 
	{
		unsigned char a;  //用无符号的,因为范围的取值
		unsigned char b;
		unsigned char c;
		unsigned char d;
		

	}ip;
};

int main()
{
	union ip_addr my_ip ;
	my_ip.addr = 176238749;  //让第一个无符号整型的值为ip地址

	printf("%d.%d.%d.%d\n", my_ip.ip.a, my_ip.ip.b, my_ip.ip.c, my_ip.ip.d);
	return 0;
}
结果如下:



猜你喜欢

转载自blog.csdn.net/miqingzhiwen/article/details/80258852