结构体的点点滴滴

文章目录

  • 结构的基本知识(结构体的声明,初始化,结构体传参,结构体的自引用,结构体内存对齐)
  • 一、位段
  • 二、枚举
  • 三、共用体和结合体


结构的基本知识

结构是一些值的集合。这些称为成员变量。结构的每个成员可以是不同类型的变量(可以是标量,数组,指针或者其他结构体)

1.结构体的声明

struct tag{ 
     number-1list;

    }variable-list; 

      (1) 例如描述一个学生:             

 struct 结构体关键字 stu结构体标签(struct stu即结构体类型){

            char name[20];(成员变量)

            short age;

            char sex[5];

            char id[5];}s1,s2,s3;(s1,s2,s3为三个全局变量)

    (2)定义结构体变量的方式: (note:typedef指给strcut stu重新起个名字为stu)                                

struct point
{
 int x;
 int y;
}p1;//声明类型同时定义p1
struct point p2;//定义变量p2
typedef struct stu
{ 
  char name[10];
  char sex[2];
}stu;

int main()
{  stu s1;
   return 0;}

    匿名结构体类型:

struct{
  char name[2];
  char sex[2];
}x;

 note:即使我们看来一样的类型,但在编译器眼中是不同的。如下代码会报warning

struct
{ char name[2];
  char sex[2];
}sa;

struct
{ char name[2];
  char sex[2];
}*psa;

int main
{ 
  psa=&a;
}

   2.结构体的初始化和访问: stu s1={"张三“,20,”男“,”11233“};

struct s
{
int a;
char c;
char arr[20];
double d;
};

struct t{
char ch[10];
struct s s1;
char*pc;};

int main()
{
char a[]="Hello bit\n";
struct t t1={"hehe",(100,'w',"hi",2.0),NULL};
printf("%s",t.ch)//打印hehe
printf("%s",t.s.arr);
}

   结构体变量访问成员 成员内部通过(.)实现的。点操作符可以同时接受俩个操作数。

 3.结构体传参

  (传入结构体变量)

typedef struct stu
{
char name[10];
short age[2];
char tele[12];
}stu;

void print(str tem)
{
printf("%s",tem.name);
printf("%d",tem.age);}


int main()
{
 stu s={"李四”,40,“123212332”};
 print(s);
}

(传入结构体变量的地址:函数内部想改变函数外部的值)

typedef struct stu{
 char name[2];
 char sex[2];
 short age;
}stu;

void print(stu*p)
{
  printf("%s\n",p->name);
  printf(“%s",p->sex);
}

int main()
{
 stu s={"李四","男”,12);
 print(&s);
}
 

  结论:传地址进去能够更加节省时间和空间(函数传参的时候,参数是需要压栈的。如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以导致性能下降)

4.结构体的自引用(结构体自己包含自己不行的,但是可以通过指针访问下一个)

数据域 地址域
1 0
2 0
3 0
typedef struct Node
{
  double d;
  int date;
  struct Node*next;
}node;

int main()
{
    struct Node n1;
    node n2;

    return 0;
}

5.结构体的内存对齐(拿空间换取时间)

    对齐规则:第一个成员在结构体变量偏移量为0的地址处

 其他成员变量要对齐到某个数字的整数倍的地址处(对齐数为编译器默认的一个对齐   数与该成员大小的最小值  vs默认为8  gcc为4)

 结构体的大小为最大对齐数的整数倍

如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍,结构体的整数 大小就是所有最大对齐数的整数倍

struct s1{
 
  char c1;
  int a;
  char c2;
};
 
struct s2{
  char c1;
  char c2;
  int a;
}

int main()
{
 struct s1 s={0};
 struct s2 s={0];
 printf("%d\n",sizeof(s1));
 printf("%d\n",sizeof(s2));
}
  

s1的所占内存:(12)    同理s2(8)

为什么存在内存对齐:(1)平台原因:不是所有的硬件平台都能访问任意地址上的任何数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则出现硬件异常。

(2)性能原因:数据结构应该在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要做俩次内存访问;而对齐的内存只需做一次内存访问。

  设计结构体的时候,我们既要满足对齐,又要节省空间,则应该让占用空间小的成员尽量集中在一起

修改默认对齐数

#prafma pack(4)//设置默认对齐数
struct s
{
  char c1;
  int c2;
  double c3;
}
#prafma pack()//取消默认对齐数

offsetof(相对于起始偏移量的偏移量)
 

一.位段(我们讲讲用结构体实现位段的能力)

 1.结构的声明和位段类似,但也有不同:

 位段的成员必须是int,unsigned int,signed int,char;

 位段的成员名后边必须有一个冒号和一个数字

位段的空间是按照需要以4个字节或者1个字节开辟的

 位段涉及很多不确定因素,位段是不跨空间的,注重可移植性的程序应该避免使用位段

struct s{
  
  int a: 2;//只需2个比特位就可以表示a
  int b:5;//只需5个比特位就可以表示b
  int c: 10;
  int d:30;
};

//47比特位————6个字节
int main()
{
  struct s s1;
  printf("%d",s1);---8
}

                                             

#include<stdio.h>

struct s{
  char a:3;
  char b:4;
  char c:5;
  char d:4;
}
int main()
{
  struct s s1;
  s1.a=10;
  s2.b=20;
  s3.c=30;
  s4.d=4;
}

 ​从右边向左边放进去

2.位段的不跨平台问题

  (1)int位段当成有符号数还是无符号数不确定

    (2)  位段中的最大为数目不确定(16位机器最大16,32位机器最大32,写成27在16位机器会有问题) 

  (3)位段在内存中从左向右分配,还是从右向左分配。

  (4)当一个结构包含俩个位段的时候,第二个位段成员比较大,无法容纳第一个位段剩余的位的时候,剩余的位舍弃还是利用不确定的。

3.位段的应用。

    上网在网络上传数据的时候,对数据包进行分装,使得数据包尽量小一些。

二.枚举:把可能出现的值一一列举

 1.定义:

enum sex//枚举类型
{
  MALE;
  FEMALE;
  SECRET;//枚举的可能取值(枚举常量)

};

int main{
enum sex x=MALE;
printf("%d %d %d",MALE,FEMALE,SECRET);//默认初始值0 1 2  但是可以自己修改
return 0;
}

2.优点:增加代码的可读性和可阅读性

 #define仅仅可以定义一种符号,但enum是有类型的

防止了命名污染

便于调试

使用方便,一次可以定义多个常量

三、共用体和结合体

     

union u
{
  char c;
  int i;
};

int main
{
 union u s;
 printf("%d",u);
}

    由于i和c共用一块空间,字节为4,i和c和u取地址之后相同。

//检测机器大小端
#include<stdio.h>
int check()
 {
   union um
   {
   char c;
   int i;
   }u;
 u.i=1;
return u.c;
}


int main()
{
 int m=check();
 if(m==1)
 printf("大端“);
 else printf("小端”);
} 

联合大小的计算:联合的大小至少是最大成员的大小。当最大成员的大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。 

   

   

おすすめ

転載: blog.csdn.net/m0_63203388/article/details/121304139