C语言几种特殊的自定义类型

24 篇文章 0 订阅
20 篇文章 0 订阅

C语言几种特殊的自定义类型

结构体

结构体的创建

可以在创建结构体的时候添加结构体的标签tag,用来为该结构体取唯一的名字,以便于和其它结构体区分开。

struct tag{
    member_list;
} variable_list;

也可以在创建结构体的时候不加标签,声明为一个匿名结构体。如:

struct
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢

在创建匿名结构体的时候要注意:如果是两个内容完全一样的结构体声明,编译器还是会把它们当做是两个不同类型的结构体。
结构体的menber_list中可以是标量、数组、指针、甚至是其它结构体,但不能是该结构体本身。

结构体的大小

一般而言,结构体的大小比结构体中所有成员的大小加起来还要大。至于为什么会这样? 大多少呢?这就涉及到一个知识点:结构体的内存对齐。

内存对齐

结构体的内存对齐是用空间换取时间的做法:为了访问未对齐的内存,处理器需要做两次内存访问;二对齐的内存只需一次内存访问。另一方面是考虑了某些平台不支持访问任意地址上任意数据的原因。

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

以下是几个例子:
例1:

struct S1
{
    char C1; //1
    int i;  //4
    char C2; //1
};   //结构体总大小为12

图解:

例二:

struct S2
{
char c1;    //1
char c2;    //1
int i;  //4
};  //结构体总大小为8

图解:

例三:

struct S3
{
    double d; //8
    char c; //1
    int i;  //4
};  //结构体总大小为16
struct S4
{
    char C1; //1
    struct S3 s3; //大小为16,对齐为8
    double d;   //8
};  //结构体总大小为32

图解:

结构体的初始化

对结构体初始化,不能在结构体内部进行。比如:

struct
{
    int x = 10; //错误的方式
    int y = 0;  //错误的方式
};

应该在定义了一个结构体变量后初始化,或者在定义结构体变量时初始化。就像对数组初始化一样。

结构体的调用

结构体是一个聚合数据类型,调用它时实际上调用的是结构体内部的成员。“.”表示对结构体内部成员的调用;“(a[i]).”表示对结构体数组a中第i个结构体内部成员的调用。若p是一个指向结构体的指针,那么对结构体成员的调用方式为“(p).”可简化为“p->”。

位段

位段的创建
  1. 位段的成员必须是 int、 unsigned int 或signed int。
  2. 位段的成员名后边有一个冒号和一个数字,这里的数字表示该变量所用的二进制位数。

比如:

struct A
{
    int _a:2;   //变量_a占2个比特位
    int _b:5;   //变量_b占5个比特位
    int _c:10;  //变量_c占10个比特位
    int _d:30;  //变量_d占10个比特位
};
位段的大小
  1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
  2. 位段的空间上是按照需要以4个字节(int )或者1个字节(char )的方式来开辟的。
  3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
struct A
{
    int _a:2;
    int _b:5;
    int _c:10;
    int _d:30;
};  //位段A的大小为8个字节

位段不存在内存对齐

图示:

位段的初始化

位段的初始化和调用方式与结构体一样

位段的调用

位段的初始化和调用方式与结构体一样

位段的跨平台问题

跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。
1. int位段被当成有符号数还是无符号数是不确定的。
2. 位段中最大位的数目不能确定。(16位机器最大16, 32位机器最大32,写成27,在16位机器会出问题。)
3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的

联合体

类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)

联合体的创建

声明联合体与声明结构体类似:

union Un
{
    char c;
    int i;
};
联合体的大小

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

union Un1
{
    char c[5];
    int i;  
};  //联合体Un1的大小为8
union Un2
{
    short c[7];
    int i;
};  //联合体Un2的大小为16
联合体的初始化

联合体的初始化和调用方式与结构体一样

联合体的调用

联合体的初始化和调用方式与结构体一样

可根据联合体的特点,进行系统大小端检验,可见大小端检测

联合体的妙用:转化IP地址
union ip_addr
{
    unsigned long addr;
    struct
    {
        unsigned char c1;
        unsigned char c2;
        unsigned char c3;
        unsigned char c4;
    }ip;
};

枚举类型

枚举类型使用关键字:enum
例如:

enum Day//星期
{
    Mon,
    Tues,
    Wed,
    Thur,
    Fri,
    Sat,
    Sun
};

enum Sex//性别
{
    MALE,
    FEMALE,
    SECRET
};

enum Color//颜⾊
{
    RED,
    GREEN,
    BLUE
};

枚举类型的成员叫做枚举常量,每一个枚举变量的取值范围只能是对应枚举类型中的所有枚举常量。(也可以是数字,但取值为数字的话就失去了枚举的意义)。
比如:

enum Color
{
    RED,
    GREEN,
    BLUE
};

int main()
{
    enum Color cloth;
    cloth = RED; 
    return 0;
}

这里的cloth的取值可以是RED、GREEN、BULE,但不能是red、green、blue、yellow等不是枚举常量的值。可以将cloth赋值为1、2、3、345等数字,但这样就没有了枚举存在的意义。

枚举变量

枚举变量是变量,是声明一个枚举类型后定义的变量。
比如:

enum Color
{
    RED,
    GREEN,
    BLUE
};

int main()
{
    enum Color cloth;   //这里的cloth就是一个枚举变量
    cloth = RED; 
    return 0;
}
枚举常量

枚举常量是常量。是声明枚举类型时枚举类型内部的成员。枚举常量可以看做是整数,默认从0开始

enum Color
{
    RED,
    GREEN,
    BLUE
};

int main()
{
    enum Color cloth;
    cloth = RED;
    printf("%d\n", cloth);  //结果为0
    printf("%d\n", GREEN);  //结果为1
    printf("%d\n", BLUE);   //结果为2
    return 0;
}

可以在声明枚举类型时改变枚举常量默认的整数。

enum Color
{
    RED,
    GREEN = 5,
    BLUE
};

int main()
{
    enum Color cloth;
    cloth = RED;
    printf("%d\n", cloth);  //结果为0
    printf("%d\n", GREEN);  //结果为5
    printf("%d\n", BLUE);   //结果为6
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值