您的位置:首页 > 其它

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

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


好了,以上内容是我对这部分内容的理解!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  结构 枚举 位段 联合