C语言 | 结构体

目录

声明

自引用

定义和初始化

内存对齐


声明

结构体的定义如下所示,struct为结构体关键字,tag为结构体的标志,member-list为结构体成员列表,variable-list为此结构体声明的变量,可以指定一个或多个结构变量。

struct tag
{
    member-list;
}variable-list;

 假如你要用结构体变量来存储学生信息,结构体的标志为"stu",member-list包括变量name来存储学生的名字,变量age来存储学生年龄,变量set来存储学生的性别,那么我们可以这样:

struct stu
{
    char name[20];
    char set;  
    int age;
};  //注意,这里的分号别忘了。

在定义结构体时,variable-list 可以为空不声明,此时只是声明了一个结构体,但是并没有定义结构体变量,还无法使用。 


 在声明结构体的时候,可以进行不完全声明,比如:

struct
{
    char a;
    char b;
    int x;
}x;

这种匿名结构体类型,只能在声明的时候定义变量使用。



自引用

何为结构体的自引用?通俗点的话来说就是在结构体中的结构中包含另一个结构体结构的变量,而这个“另一个”指的是自己,就像这样:

//下面两种声明,哪种更合适?
//1.
struct Node
{
    char a;
    struct Node next;
};
//2.
struct Node
{
    char a;
    struct Node* next;
};

在结构体Node的结构中,包含自身结构定义的变量next。那么,存在一个问题,上面两种写法哪种才是正确的呢?

答案是第二种,因为指针的大小是固定的,因此编译器可以在解析结构struct Node时确定其大小,如果结构体在声明时结构成员包含自身结构定义的变量next,而不是其指针,则无法确定其大小,这是一个循环定义。

当然,可以引用自身,那么也可以嵌套别的结构体



定义和初始化

在上面的结构体声明时说了,"在定义结构体时,variable-list 可以为空不声明,此时只是声明了一个结构体,但是并没有定义结构体变量,还无法使用"。有了结构体类型,定义其变量很简单:

struct stu
{
    char name[20];
    char set;
    int age;
}a;    //声明结构体的同时定义其一个变量a.

//使用变量a:
a = {"zhangsan",'Y',20};


内存对齐

我们知道,char类型变量的大小是1个字节,int类型变量的大小是4个字节,指针类型变量的大小是4/8 个字节,那么结构体变量的大小呢?我们先运行以下代码看看:

#include 
struct stu1
{
    char a;
    char b;
    int c;
};
struct stu2
{
    char a;
    int b;
    char c;
};

int main()
{
    printf("stu1的大小是%d\n",sizeof(struct stu1));
    printf("stu2的大小是%d\n",sizeof(struct stu2));
    return 0;
}

运行结果如下:

C语言 | 结构体_第1张图片

那么,既然stu1和stu2的结构成员一样,顺序不一样,字节大小却不一样,是因为结构体存在内存对齐。


结构体的对齐规则:

        1.第一个成员在与结构体变量偏移量为0的地址处。

        2.其它成员变量在对齐数的整数倍的地址处。

                对齐数 = 编译器默认的对齐数 与 该成员大小 的最小值
                VS编译器默认对齐数为8(可修改),Linux无默认对齐数

        3.结构体总大小为最大对齐数的整数倍。
        4.如果结构体的结构成员嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

C语言 | 结构体_第2张图片


那么,为什么结构体需要内存对齐?

1.平台原因,不是所有的硬件平台都能访问任意地址上的任意数据的,某些硬件平台只能在某些地址处去某些特定类型的数据,否则抛出硬件异常,需要考虑其移植性。
2.性能原因,为了访问未对齐的内存,处理器需要作两次内存访问,因此在数据结构上应该尽可能地在自然边界上对齐。

你可能感兴趣的:(c语言,c++,开发语言)