2020/3/5华中科技大学计算机学院1C语言程序设计TheCProgrammingLanguage华中科技大学计算机学院曹计昌2020/3/5华中科技大学计算机学院2*10.7联合10.7.1联合类型的定义与结构类似,联合类型也是一种构造类型。一个联合类型中包含有多个成员,这些成员共享共同的存储区域,但这些成员并不同时存在;联合存储区域的大小由各个成员中所占字节数最大的成员决定;在任何时刻,各个成员中只能有一个成员拥有该存储。除了用关键字union取代struct之外,联合类型的定义、联合变量的声明、以及联合成员的引用在语法上与结构完全相同。2020/3/5华中科技大学计算机学院3如果有3个不同数据类型(char,short,long)的变量要分时共用一个共同的存储区域,则可以定义如下的联合类型:unionchl{charc;shorth;longl;};这里chl是所定义的联合类型的联合名(tag),它与union一起形成一个unionchl的联合类型。c、h、l是联合类型的成员。2020/3/5华中科技大学计算机学院410.7.2联合变量的声明、初始化及联合成员的引用定义了unionchl的联合类型后,可以通过:unionchlu;来声明一个unionchl类型的变量。也可以在定义unionchl联合类型的同时来声明相应的联合变量。如:unionchl{charc;shorth;longl;}v={ˊ9ˊ};它在定义unionchl联合类型的同时声明了联合类型的变量v,并且对其进行了初始化。在不产生二义的情况下,往往简称联合类型的变量为联合。2020/3/5华中科技大学计算机学院5联合变量的声明、初始化值得注意的是,联合变量的初始化与结构的初始化在形式上相同,都应该用花括号界定初值,但联合是一种特殊形式的构造类型的数据,在同一时刻它只拥有其中的一个成员。因此,初始化时只能对联合的第1个成员进行初始化。换言之,初值表中只能包含与第1个成员数据类型相同的一个初值。如上面例子中的v={'9'}。也可以:unionchlv={ˊ9ˊ},w={ˊaˊ};2020/3/5华中科技大学计算机学院6例10.12通过例子对联合的特性进行进一步分析。#includestdio.hunionchl{charc;shorth;longl;};voidshow(unionchl*pu);voidshow_memoy(unionchl*pu);2020/3/5华中科技大学计算机学院7voidmain(void){unionchlu;printf(sizeofuis%d\n,sizeof(u));u.l=0x31323334L;show(&u);show_memoy(&u);u.h=0x3638;show(&u);show_memoy(&u);}2020/3/5华中科技大学计算机学院8voidshow(unionchl*pu){printf(charformat:%c\n,(*pu).c);printf(intformat:%hx\n,pu-h);printf(longformat:%lx\n,(*pu).l);}voidshow_memoy(unionchl*pu){char*p=(char*)pu;inti=0;while(i4){printf(addr%dthbyteofuis0x%p\t,i,p+i);printf(theASCIIin%dthbyteofuis%c\n,i,*(p+i));i++;}}2020/3/5华中科技大学计算机学院9程序的运行结果如下:sizeofuis4charformat:4intformat:3334longformat:31323334addr0thbyteofuis0xFFD8theASCIIin0thbyteofuis4addr1thbyteofuis0xFFD9theASCIIin1thbyteofuis3addr2thbyteofuis0xFFDAtheASCIIin2thbyteofuis2addr3thbyteofuis0xFFDBtheASCIIin3thbyteofuis1charformat:8intformat:3638longformat:31323638addr0thbyteofuis0xFFD8theASCIIin0thbyteofuis8addr1thbyteofuis0xFFD9theASCIIin1thbyteofuis6addr2thbyteofuis0xFFDAtheASCIIin2thbyteofuis2addr3thbyteofuis0xFFDBtheASCIIin3thbyteofuis12020/3/5华中科技大学计算机学院10对程序和程序的运行结果可以做如下分析:1)联合的存储结构从sizeof(u)的结果为4可以看出,联合u所占存储的大小为4个字节,这正好是长整型成员l所占存储的大小。这4个字节的存储是连续的,地址从0xFFD8至0xFFDB。u.l的值为0x31323334L,u的存储描述为:2020/3/5华中科技大学计算机学院112)联合的指针可以声明联合类型的指针。如:unionchlv,*pv=&v;说明了一个unionchl类型的指针pv,并且取出v地址对pv进行初始化,使联合指针pv指向了联合变量v。值得注意的是,联合所有成员的地址和联合变量的地址都是相同的。因为所有成员都是从同一存储空间的边界(低地址)开始存放。但是,不同成员指针值(地址值)的类型是不相同的。因此,&u,&u.c,&u.h,&u.l的地址都相同。但&u的数据类型是unionchl*。&u.c的数据类型是char*。&u.h的数据类型是intshort*。&u.l的数据类型是longint*。2020/3/5华中科技大学计算机学院123)联合成员的引用可以通过联合变量和“.”操作符,以及指向联合变量的指针和“-”操作符来引用联合成员。从u.l,(*pu).c,pu-h三个表达式中可以归纳出对联合成员的引用形式为:(1)联合变量名.成员名。(2)(*指向联合变量的指针).成员名。(3)指向联合变量的指针-成员名。例如:u.c或(*pu).c或pu-c都表示引用联合成员c,类型是char。u.h或(*pu).h或pu-h都表示引用联合成员h,类型是short。u.l或(*pu).l或pu-l都表示引用联合成员c,类型是long。而u.c=ˊaˊ,(*pu).h=0x3839,以及pu-l=0x31323334L分别表示对联合u的成员c、h、l的赋值操作。2020/3/5华中科技大学计算机学院134)共享存储的特点在main函数中,u.l=0x31323334L;赋值语句产生的存储可由表10-3描述,各字节的地址由高向低,依次存放0x31、0x32、0x33、0x34,联合u由成员l使用。由show函数和相应的运行结果可以看出,此时如果按照(*pu).c解释,输出的只是共享存储的低字节的内容0x34或字符ˊ4ˊ。如果按照,pu-h解释,输出的只是共享存储的低端2个字节的内容0x33和0x34。执行u.h=0x3638;语句之后,联合u由成员h使用。该语句修改了共享存储低端2个字节的内容,但是高端2个字节的内容没有变化。2020/3/5华中科技大学计算机学院145)相容性操作联合中允许存储不同类型的数据,对某个时刻存储的数据,其所允许的操作也有所不同,有些操作对该类型的数据是相容的,但有些操作却不相容(得不到正确结果)。由于语法上合法,编译器对这种情况不会报错,但运算的结果却不正确。假如在unionchl中增加一个成员(其它都不变),如:floatf;则在show函数中,如果执行语句为:printf(floatformat:%f\n,pu-f);则得到是不正确的结果0.00,而其他语句中操作却是相容的。2020/3/5华中科技大学计算机学院15*10.8字段结构由多个相邻的二进制位可以组成结构或者联合中的整型或无符号整型成员,这些个相邻的二进制位被称为字段(bitfield),对应的成员称为结构或联合的字段成员,以字段为成员的结构称为字段结构。组成字段的二进制位的数目成为该字段的宽度,它是一个非负的整型常量表达式。字段结构在操作系统,编译程序,嵌入式系统的C语言编程方面使用较多。例如,stdio.h中关于文件状态成员flags的取值就规定了1为读状态,2为写状态,4为缓冲数据状态等等。这些数据都是一些值很小的整数,没有必要用int或char变量来存储每一个值。通常对若干个特征中的每个特征按照取值的大小分配合适的二进制位,然后将它们组织成为字段封装到一个int或char变量中。这样就可以通过字段名对相应的二进制位或位串进行操作,而不必采用前面章节介绍的位运算。2020/3/5华中科技大学计算机学院1610.8.1字段结构类型的定义字段结构也属于构造类型,因此要先定义字段结构类型,再声明字段结构变量,然后再对字段结构变量中的成员进行操作。考虑十字路口的交通灯.颜色枚举类型的声明如下:enumcolor{OFF=0,RED=1,YELLOW=2,GREEN=3};2020/3/5华中科技大学计算机学院17structtraffic_light{unsignedshortinteast:2;/*东组灯状态字段*/unsignedshortintsouth:2;/*南组灯状态字段*/unsignedshortintwest:2;/*西组灯状态字段*/unsignedshortintnorth:2;/*北组灯状态字段*/unsignedshortintreserve:8;/*保留字段*/unsignedshortinteast_on:4;/*东组灯开通时间*/unsignedshortintsouth_on:4;/*南组灯开通时间*/unsignedshortintwest_on:4;/*西组灯开通时间*/unsignedshortintnorth_on:4;/*北组灯开通时间*/};4组交通灯的字段结构类型的声明2020/3/5华中科技大学计算机学院184组交通灯的字段结构类型的简略形式声明structtraffic_light{unsignedshortinteast:2,south:2,west:2,north:2,reserve:8;unsignedshortinteast_on:4,south_on:4,west_on:4,north_on:4;};上面声明了一个structtraffic_light的字段结构类型,east、south、…、north_on为它的字段成员,字段成员往往也简称为字段。冒号后面的整数说明了成员的字段宽度,字段宽度是一个非负的整型常量表达式。上面定义中,其中字段宽度为2的四个成员用unsignedchar更加简练,但TurboC中不支持unsignedchar,因此用unsignedshortint。2020/3/5华中科技大学计算机学院1910.8.2字段结构类型变量的声明及成员的引用可以先定义字段结构类型,再声明字段结构类型的变量。如:structtraffic_lightJiedaokou;它声明了structtraffic_light的字段结构类型变量Jiedaokou。同时,还可以在声明字段结构类型的变量的同时对其进行初始化。如:structtraffic_lightJiedaokou={0,0,0,0,0,0,0,0,0};它将east、…、north_on这9个字段成员都初始化为0。2020/3/5华中科技大学计算机学院20也可以在定义字段结构类型的同时声明字段结构变量并对其成员进行初始化。如:structtraffic_light{unsignedshortinteast:2,south:2,west:2,north:2,reserve