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

结构体:

我们之前学过数组吧!结构体和它类似。
1.结构体的声明
结构是一些值的集合,这些值称为成员变量。结构的每个成员变量可以为不同的类型。

其声明为:

struct tag //tag为标签
{
    member-list;//不可省略。
}variable-list;//分号不能丢

标签和变量名至少存在一个。

下面给出一断代码,看看是否合法?

struct {
    int a;
    char b;
    float c;


struct {
    int a;
    char b;
    float c;

}y[20],*z; //y是一个结构体数组,z是一个指针,指,z是一个指针,指向此类型结构

z=&x;//不合法!
这两个声明被当做不同的两种类型。即使其结构体成员不同。

结构体的成员

其成员可以是标量,数组,指针甚至是其他结构体。
结构体的成员地址依次增大,结构体本身的地址和成员首地址相同。(关于这部分内容有需要证明者可自行打印证明哦!)

结构体成员的访问

(1).通过点操作符(.)访问,接受两个参数。结合性从左至右。
(2).通过->操作符访问。左操作数必须为一个指向结构的指针。

代码说明

struct Stu {
    char name[20];
    int age;
};

    struct Stu s;//结构体变量
    struct Stu *p;
    (*p).age = 20;
    p->age = 20;
    s.age = 20;

结构体的自引用

提个问题先:在一个结构体内包含一个类型为该本身的成员是否可以呢?
结构体自引用要使用完整的标签
举栗说明:

struct Stu {
    char name[20];
    int age;
    struct Stu x;  //编译器报错,“x”使用未定义的 struct“Stu”    ,编译器不确定其长度

};


正确方式为:
struct Stu {
    char name[20];
    int age;
    struct Stu *x;//x是一个指针,指向同一类型的不同结构。编译器确定其长度,合法。
};

4.结构体的初始化
这里只要记住一句话就可以了,结构体本身允许整体初始化(使用花括号),不允许整体赋值。

5.结构体的内存对齐

注意啦!此部分内容是结构体部分的重点。
结构体的内存对齐是拿空间来换取时间的做法。

为什么存在内存对齐?

(1).平台原因(移植原因)
不是所有的平台都可访问任意地址上的任意数据,某些只能在某些地址处取某些特定的数据,否则会抛出异常。
(2).性能原因
为了访问未对齐的内存,处理器需作两次内存访问,二对齐的内存只需访问一次。

如何计算?

首先必须了解结构体的对齐规则:
a.第一个成员与结构体变量偏移量为0的地址处;
b.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处;
对齐数=编译器默认的对齐数与该成员大小的较小值。
vs中默认最大对齐数为8 //用#pragma pack ()设置时应小于等于8;
linux默认最大对齐数为4;
c.结构体总大小为最大对齐数的整数倍。
d.若嵌套了结构体,嵌套的结构体对齐到自己最大对齐数的整数倍。结构体的整体大小就是所有最大对齐数(含嵌套的结构体最大对齐数)的整数倍。

接下来举栗说明:
例1:

struct S1
{
    char c1;
    int i;
    char c2;
};
printf("%d\n", sizeof(struct S1));//结果12

这里写图片描述
例2:

struct S2
{
    char c1;
    char c2;
    int i;
};
printf("%d\n", sizeof(struct S2));//结果为8

这里写图片描述

例3:

struct S3
{
    double d;
    char c;
    int i;
};

struct S4
{
    char c1;//1+7
    struct S3 s3;//8+16
    double d; //8+16+8=32
};

printf("%d\n", sizeof(struct S4));//32

例4:

//结构体嵌套类型
//用上例的S3结构体,最大对齐数为8
vs2013下

struct S5
{
    char c1; //1+7=8
    struct S3 a[3]; //8+16*3=56
    char ch[5];//56+5=61
    struct S3 *p;//61+3+4=68
    double d;//68++4+8=80
    short b[3];//80+6+2=88
};
printf("%d\n", sizeof(struct S5));//88

Linux下为80//最大对齐数4

struct S5
{
    char c1;//!+3=4
    struct S3 a[3];//4+16*3=52
    char ch[5];//52+5=57
    struct S3 *p;//57+3+4=64
    double d;//64+8=72
    short b[3];//72+6+2=80
};

5.结构体传参

这块用代码说明即可:

struct S
{
    int data[1000];
    int num;
};
struct S s = { { 1, 2, 3, 4 }, 1000 };
//结构体传参
void print1(struct S s)
{
      sleep(100);
    printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S *ps)
{
    sleep(100);
    printf("%d\n", ps->num);
}
int main()
{
    print1(s);  //传结构体,可以借用函数栈帧理解,系统开销大
    print2(&s); //传地址,每次4字节

    system("pause");
    return 0;
}

运行后即可发现二者时间不同

位段

位段的声明和结构是类似的,有两个不同:

1.位段的成员必须是 intunsigned intsigned intchar2.位段的成员名后边有一个冒号和一个数字。
struct A 
{ 
     int_a:2; 
     int_b:5; 
     int_c:10; 
     int_d:30; 
};
printf("%d\n", sizeof(structA));//8 为什么呢?

见图:

这里写图片描述

吃个栗子吧:

typedef struct{  
    int a:2;  
    int b:2;  
    int c:1;  
}test;  
int main(){  
    test t;  
    t.a=1;  
    t.b=3;  
    t.c=1;  
    printf("%d\n%d\n%d\n",t.a,t.b,t.c);  
    return 0;  
}  

结果:
1,-1,-1

为什么?
int a:2表示a占2位,即二进制a=01,因此输出1

b占两位,b=11,但是由于是%d输出,所以先将b转化成32int型,由于最高位是1,所以默认其为负数,所以扩展为11111111 11111111 11111111 11111111

即-1,c类似

注意:位段是不跨平台的,注重可移植的程序应该避免使用位段。

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

枚举

顾名思义即一一列举,其本质为整型

enum Color//颜色
{
    RED,
    GREEN,
    BLUE

};

{}中的内容是枚举类型的可能取值,也叫 枚举常量 。这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。

enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现
类型的差异。

联合

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

union Un 
{ 
    char c; 
    int i; 
}un;
printf("%d\n", sizeof(un));//答案为4
union Un 
{ 
   int i; 
   char c; 
}; 
union Un un;

printf("%d\n", &(un.i)); 
printf("%d\n", &(un.c));

运行后发现结果相同。
//下面输出的结果是什么?
un.i = 0x11223344; 
un.c = 0x55; 
printf("%x\n", un.i); 

结果为:0x11223355

这里牵扯计算机大小端的问题,具体内容可见
http://blog.csdn.net/kai29/article/details/78577698

联合大小的计算

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

举例:

union Un1
{ 
  char c[5]; 
  int i; 
}; 
union Un2
{ 
  short c[7]; 
  int i; 
}; 
//下面输出的结果是什么?
printf("%d\n", sizeof(union Un1)); //8
printf("%d\n", sizeof(union Un2)); //16

好了,以上内容是我对这部分内容的理解!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值