天天看点

如何在结构体里面套结构体_C语言难点之结构体

结构体的定义

对于结构体的定义,我想讲的不是基本的结构体定义,而是基本的定义与typedef结合使用的情况,我在刚开始学的时候比较蒙,所以这里总结一下。

struct control
{
    int a;
    char b;
    float c;
};
           

注意结构体定义结束的分号一定要有。在这个声明之后,就可以进行结构体元素的定义了,与面向对象编程类型,定义了类,可以用类来定义对象是一样的,用这个结构体来定义结构。

struct control con;
struct control simple;
(变量名随意起的,不符合命名规范)
           

如上,我们就定义了两个结构。但是如果我们使用了的定义

struct control
{
    int a;
    char b;
    float c;
}control;
typedef struct control
{
    int a;
    char b;
    float c;
}control,* p_control;
           

在不使用typedef的时候,其实是定义的结构,与只有声明不同的是在声明的同时就定了结构,在程序里面就可以使用结构control,而对于使用了typedef的,就是声明,因为这是typedef的作用,声明新的变量名,对于第二个声明,就是将结构取了别名,在声明之后struct control与control是一样的,struct control * 与p_control是相同的。看例子

struct control con;
struct control *simple;
control con;
p_control simple;
           

这两个定义就是相同的,定义了结构体con和结构体指针simple。

这里来介绍一个分析typedef给创建新类型后如何分析定义的方法。

typedef int Num[100];
Num t;
           

这个t定义的是什么呢?Num[100]就是int的别名吗?Num t相当于int t吗?显然不是的,定义t是一个拥有100个整型元素的数组。怎么来分析呢?就是把typedef这一行的typedef去掉,然后把Num换成t,那么就变成了

int t[100];
           

再来看一个例子

typedef void (*p_fun)(void);
p_fun fun;
           

这就是定义了一个没有输入,没有返回值的函数指针fun.使用前面的分析方法来分析一下,去掉typedef

void (*p_fun)(void);
           

将p_fun 替换为fun。

void (*fun)(void);
           

是的,就是一个函数指针。

结构体的对齐问题

对于结构体的对齐问题,也是一个笔试题常考点,考查一个结构体占多少字节。

typedef struct control
{
   char name;
   char age;
   short sh;
   int num;
   double d;
};
typedef struct control
{
   char name;
   short sh;
   char age;
   int num;
   double d;
};
           

怎么样?感觉有区别吗?

答案是当然有区别了,所在内存的字节数不一样,按照32位的4字节对齐来分析这个问题。首先说一下结构体对齐的原则:

  1. 分析是将首地址按照0来算,比较简单(因为真实地址你也不知道呀!只有编译器知道)
  2. 每个成员的首地址必须是这个成员所占字节数的整数倍关系,比如说char类型占1个字节,那么起始就无所谓了,都是整数倍关系,short占两个字节,那么起始地址必须是偶数,就是上面的第二个结构体,char地址从0占了一个字节,此时short定义,与char之间必须空一个字节,因为这样才能保证起始地址为2,是2个字节的整数倍。如果使用 #pragma pack(4) 来声明,那么double也要按4字节对齐。
  3. 整个结构体所占字节总数必须是所有基本元素类型中占有字节最多的整数倍,比如结构体里面有double占8个字节,那么整个结构体占的字节数应该是8的整数倍,否则需要补齐。但是如果使用 #pragma pack(4) 来声明对齐的字节数为4,那么整个结构占的字节数就要是4的整数倍了。

根据以上原理来分析,第一个结构体前两个都是char类型的结构体,所以就可以占的字节为0和1,之后为short类型,两个字节,恰好此时起始地址为2,所以不需填补,现在起始地址为4,接下来时int型,占4个字节,恰好也是整数倍,也不需填充;现在起始地址为8,double类型占8个字节,也是整数倍,不需填充,整个结构体现在就是1+1+2+4+8=16个字节,也是8的整数倍,所以这个结构体没有填充,占16个字节。

如何在结构体里面套结构体_C语言难点之结构体
如何在结构体里面套结构体_C语言难点之结构体

下面再来分析第二个结构体,起始为0,char类型占据一个字节,现在起始地址为1,之后是short类型,占两个字节,所以需要填充一个字节,使起始地址为2,是整数倍(规则2),那么现在起始地址为4,接下来是char类型占一个字节,现在起始地址为5,接下来是int型,因为int型占4个字节,所以需要是4的整数倍,需要填充三个字节,让起始地址为8才可以,在int之后,目前起始地址为12,double为8个字节,那么起始地址就得是16,所以填充4个字节。那么现在一共是1+1+2+1+3+4+4+8=24。24是8的整数倍符合第三个规则。所以结构体为24字节。

如何在结构体里面套结构体_C语言难点之结构体
如何在结构体里面套结构体_C语言难点之结构体
typedef struct control  
    {  
        char ch[20];  
        double b;     
        char name;  
        int num;    
        short sh;      
    }control;
           

在来看一个复杂一点的,相信你这个时候已经可以分析出来这个结构占42个字节,但是这个时候要注意第三个规则,这个结构体的做大的基本类型是double,占8个字节,所以此时在后面需要补足6个字节,占48个字节,是8的整数倍。所以这个结构体的字节数为48.

如何在结构体里面套结构体_C语言难点之结构体
如何在结构体里面套结构体_C语言难点之结构体

在来看当使用#pragma pack(4)时,这个结构体所占的字节数。

如何在结构体里面套结构体_C语言难点之结构体
如何在结构体里面套结构体_C语言难点之结构体

这就是今天总结的关于结构体的知识,欢迎讨论交流。 欢迎关注我,一起成长,一起玩编程。