自定义类型:结构体、枚举、联合

C语言的三种自定义类型:结构体,枚举,联合
一、结构体
1.结构体的声明
struct tag
{
member-list;//在C语言中定义结构体时,其成员变量不能为空
}variable-list;
例:
struct student //最好不要省略结构体标签(tag),否则以后定义结构体变量的时候就必须在此处定义
{
char name[20];
char id[20];
int age;
};//切记分号不能丢
2.结构体的成员
结构体的成员可以使标量、数组、指针,或者其他结构体
访问结构体变量成员使用点操作符(.),但当结构体访问指向变量的成员是一个指向结构体的指针的时候可以使用指向操作符(->);
例:
struct S
{
char name[20];
int age;
}s;

void printf(struct S* ps)
{
    printf("name = %s, age = %d\n",ps->name, ps->age);
}

3.结构体的初始化
例:
struct A
{
int x;
int y;
};
struct A a = {x, y};//定义变量同时赋值

struct B
{
int data;
struct A a;
struct B *B = b;
}n = {10, { 4, 5}, NULL};//结构体嵌套初始化
4.结构体内存对齐
why?
由于有些硬件只能在某些地质处取某些特定类型的数据,所以为了提高CPU的访问速率,就需要内存对齐。
总体来说结构体内存对齐就是用空间来唤起时间,也就是增加其空间来缩短时间。
所以在设计结构体的时候,为了满足结构对齐,又要节省空间,我们可以让占用空间小的成员尽量集中在一起。
对齐规则:

  • 1.第一个成员在与结构体变量偏移量为0的地址。(第一个成员也有对齐数)
  • 2.对齐数=编译器默认的一个对齐数和该成员大小的较小值。新元素的起始偏移量是对齐数的整数倍。我的偏移量必须可以整除对齐数。(Windows和Linux的默认值都是4,VS默认的是8。)
  • 3.结构体总大小为最大对齐数的整数倍。
  • 4.嵌套结构体中,嵌套的结构体对齐到自己最大对齐数的整数倍,结构体的整体大小是所有最大对齐数的(含嵌套结构体的对齐数,结构体的对齐数就是它内部的最大对齐数)整数倍。
    注:#pragma pack(int) 改变对齐数,当其不传参数时,恢复默认,在Linux中,设置对齐数时最好别超过默认最大对齐数。
    对齐数在设置的时候必须设置位2的整数倍。

4.位段
位段是已压缩存储为目标,为了经量的节省空,而产生的结构体的衍生品,它允许访问某个元素的某几个字节
位段的声明和结构体类似,但有两点不同:

  • 1.位段的成员必须是int、unsigned int、signed int
  • 2.位段的成员名后边有一个冒号和数字(数字表示使用变量的几个比特位)
    例:
struct A
{
    int _a:2;
    int _b:3;
    int _c:;
};

位段存储:位段存储在存储时都采用亚索存储的方式,通俗来讲就是,在一个四字节中,能在一起大家就先在一起,当挤不下的时候就重新开辟一个四字节独立存放。
如果对位段的任何一个元素写入,超范围时,超出的部分直接被丢弃,不会影响其他元素。
位段一般不考虑内存对齐问题,但当位段和结构体混用时,需要考虑,但出现情况非常少。
位段的跨平台问题(尽量少用):

  • 因为位段int是有符号数还是无符号数是不确定的,所以会导致位段结构体本质上行为是不确定的。
  • 位段中最大的卫士不确定。
  • 位段中的成员在内存中是分配的方向不确定。
  • 当一个结构体有两个位段的时候,第二个位段超出了第一个位段剩余的位数时,是舍弃还是利用是不确定的。

    二、枚举
    1.定义:可以被一一列举的类型和宏很相像。
    2.枚举类型的定义
    例:

enum Color
{
    RED = 1,
    GREEN = 2,
    BLUE = 4
};

定义的枚举变量必须被自己的枚举常量赋值。
枚举常量就是整数,但是对枚举变量赋值我们依旧不能直接对其直接赋整数,而是要给其赋上枚举常量,这是为了增加枚举的可读性。
3.枚举的优点:

  • 增加代码的可读性和可维护性,
  • 宏实在预处理时进行处理,而枚举实在编译的时候就被检查,可以增加代码的严谨性。
  • 防止命名污染(封装)。
  • 便与调试
  • 使用便捷,可以一次定义多个常量。
    三、联合
    1、定义:联合的最大特征是,联合内的所有成员公用一个内存空间。
    例:
union Un
{
    char c;
    int i;
};

联合体的大小通常指联合体内最大成员的大小。
联合体内的所有成员都可以是联合体的第一个成员,甚至是唯一一个成员。
联合体内多有成员的地址,和联合体变量的地址在数值上是相等的。
联合体存放数据时是从内存空间的最低地址开始存放(小端,大端与其相反)。
2、联合体大小的计算

  • 联合体的大小至少为最大成员的大小;
  • 联合体还要考虑内存对齐问题,即当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
    3、联合体的应用
    例:
union ip_addr
{
    unsigned long addr;
    struct
    {
        unsigned char c1;
        unsigned char c2;
        unsigned char c3;
        unsigned char c4;
    }ip;
}

int main()
{
    union ip_addr my_ip;
    my_ip.add = 1921681155;
    printf("%d.%d.%d.%d\n",my_ip.ip.c4,my_ip.ip.c3,my_ip.ip.c2,my_ip.ip.c1);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值