自定义类型:结构体,枚举,联合
2017-11-24 19:14
411 查看
结构体:
我们之前学过数组吧!结构体和它类似。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.位段的成员必须是 int、unsigned int 或signed int 或char。 2.位段的成员名后边有一个冒号和一个数字。
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转化成32位int型,由于最高位是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
好了,以上内容是我对这部分内容的理解!
相关文章推荐
- 自定义类型:结构体、枚举、联合
- 自定义类型(结构体、枚举、联合)以及内存对齐问题
- 自定义类型(结构体,枚举,联合,位段)
- 自定义类型:结构体、枚举、联合
- 自定义类型(结构体、位段、枚举和联合)
- 自定义类型:结构体,枚举,联合
- 自定义类型——结构体,枚举,联合
- 自定义类型:结构体 位段 枚举 联合
- 自定义类型(结构体,位段,枚举,联合)总结
- 自定义类型——结构体、枚举、联合
- 自定义类型:结构体,枚举,联合部分知识总结
- Android For JNI(五)——C语言多级指针,结构体,联合体,枚举,自定义类型
- 自定义类型部分知识写一篇博客。 知识点: >结构体类型创建 >结构体初始化 >结构体内存对齐 >位段,位段计算机大小。 >枚举+联合。
- 结构体、位段以及联合的计算——自定义类型部分知识
- C语言基础(六)- 结构体、共用体、枚举和typeof自定义类型
- 自定义类型中结构体、枚举等,结构体内存对齐相关要点总结
- 自定义类型:结构体,枚举,联合体
- C++ 自定义数据类型:结构体,共用体,枚举
- 复合数据类型,结构体,联合,枚举
- 自定义类型---->结构体,枚举,联合体