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

来源:互联网 发布:手机淘宝查看天猫积分 编辑:程序博客网 时间:2024/06/05 05:58

一,结构体:
我们之前学过数组吧!结构体和它类似。
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;//不合法!这两个声明被当做不同的两种类型。即使其结构体成员不同。

2,。结构体的成员

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

结构体成员的访问

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

代码说明

struct Stu {    char name[20];    int age;};    struct Stu s;//结构体变量    struct Stu *p;    (*p).age = 20;    p->age = 20;    s.age = 20;

3.结构体的自引用

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

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结构体,最大对齐数为8vs2013下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));//88Linux下为80//最大对齐数4struct 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,因此输出1b占两位,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)); //8printf("%d\n", sizeof(union Un2)); //16

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