对结构体联合体的认识

来源:互联网 发布:js cookie不起作用 编辑:程序博客网 时间:2024/05/19 17:50

C语言提供了两种类型的聚合数据类型:数组和结构。数组是相同类型元素的集合,它的每个元素可以通过数组的下标方式访问也可以通过指针解引用的方式进行访问。

数组访问元素的方式如图

结构体也是一些值的集合,这些值称为它的成员,如果要访问这些成员必须要通过这些结构体成员自己的名字进行访问

struct A{char a;int b;double c;};

这里只是声明了一个结构体这个结构体包含三个结构体成员,分别是char a,int b,和double c.但这仅仅是声明了一个结构体类型,并没有为它分配内存,我们知道定义和声明最大的区别在于有无分配内存很显然这是声明不是定义。

结构体本身并不会被作为数据而开辟内存,真正作为数据而在内存中存储的是这种结构体所定义的变量

对结构体变量成员的访问是通过.操作符来访问的,下面例子对结构体成员a进行访问时就是通过student.a来进行访问的。

看下面这个例子:

#include<stdio.h>#include<stdlib.h>struct A{char a;int b;double c;}student;int main(){printf("%p\n", &student);printf("%p\n", &(student.a));system("pause");return 0;}


从这个例子我们可以看出当创建了一个结构体变量时它是为这个结构体分配内存了,并且结构体的首地址和第一个结构体成员的首地址相同。

此外在结构体中还应该注意: 自引用问题:在结构体内部包含一个类型为该结构体本身的成员。

#include<stdio.h>#include<stdlib.h>struct A{char a;int b;double c;struct A obj;};
这个在编译期间是不会通过的,它会报一个错误说obj使用未定义的struct A。原因就在于struct A中包含了他自己的成员obj,而这个成员又是另一个完整的结构,这样一直递归一直重复找不到递归出口,因此是错误的。
#include<stdio.h>#include<stdlib.h>struct A{char a;int b;double c;struct A *obj;};int main(){system("pause");return 0;}
(⊙o⊙)...而这个声明却是能编译
因为obj现在是一个指向结构体的指针他是一个指针明确了大小为4个字节所以这种自引用是合法的。

#include<stdio.h>#include<stdlib.h>typedef struct {char a;int b;double c;    A *obj;}A;int main(){system("pause");return 0;}
这个例子却无法编译通过,我们都知道typedef是给结构体类型起一个新名字叫A但是它的类型名是在尾部才被定义的在内部没有被定义,因此是错误的

正确的让他在开始类型就被定义:

#include<stdio.h>#include<stdlib.h>typedef struct B{char a;int b;double c;   struct B *obj;}A;int main(){system("pause");return 0;}
使用不完整的声明方式实现结构体中套结构体并且至少有一个结构体在在另一个结构体内部以指针的形式存在。

关于结构体内存对齐的问题:

在VS2013环境下,它的最大对齐数为8当然我们也可以使用#pragma pack(N)的方式来修改它的最大对齐数但是N只能比8小不能比8大

#include<stdio.h>#include<stdlib.h>struct A{char a;int b;double c;struct B{double aa;char bb;int cc;};double x;};int main(){   printf("%d", sizeof(struct A));system("pause");return 0;}

结果为 :40

分析:结构内存对齐规则:1、第一个结构体成员不需要对齐,

                2、其他成员要对齐到某个数字(对齐数)的整数倍的地址处。

                 //对齐数=编译器默认的一个对齐数与该成员大小的较小值。

                 VS 中默认为8

                 LINUX中默认为4 

               3、结构体的总大小为最大对齐数的整数倍(每一个成员变量除了第一个成员都有对对齐数)                      

#include<stdio.h>#include<stdlib.h>struct B{int a;char b;double c;//4+1+3+8=16};union A{int a;char b;char c[5];struct B d;}obj;//16int main(){printf("%d", sizeof(obj));system("pause");return 0;}


联合体:在进行某些算法的C语言编程的时候,需要使几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作“共用体”类型结构,简称共用体,也叫联合体。联合”与“结构”有一些相似之处。但两者有本质上的不同。在结构中各成员有各自的内存空间,一个结构体变量的总长度大于等于各成员长度之和。而在“联合”中,各成员共享一段内存空间,一个联合变量的长度等于各成员中最长的长度。

因此我们也可以用联合体来判断你的计算机是大端模式还是小端模式

大端模式:数据位的高位在内存的低地址,数据位的低位在内存的高地址。

小端模式:数据位的高位在内存的高地址,数据位的低位在内存的低地址。

代码如下:

#include<stdio.h>#include<stdlib.h>int checksystem(){union check{int a;char b;}c; c.a = 1; return(c.b);}int main(){if (checksystem()){printf("该计算机为小端模式");}system("pause");return 0;}


我们可以看到数据的地位存放在低地址上,因此为该机器为小端模式。

地址从左往右依次增大从上往下依次增大。每一个字节右边低左边高。

关于联合体的内存对齐问题:

联合体union

      当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体(union)。在C Programming Language 一书中对于联合体是这么描述的:

     1)联合体是一个结构;

     2)它的所有成员相对于基地址的偏移量都为0;

     3)此结构空间要大到足够容纳最"宽"的成员;

     4)其对齐方式要适合其中所有的成员;

下面解释这四条描述:

     由于联合体中的所有成员是共享一段内存的,因此每个成员的存放首地址相对于于联合体变量的基地址的偏移量为0,即所有成员的首地址都是一样的。为了使得所有成员能够共享一段内存,因此该空间必须足够容纳这些成员中最宽的成员。对于这句“对齐方式要适合其中所有的成员”是指其必须符合所有成员的自身对齐方式。

#include<stdio.h>#include<stdlib.h>struct B{int a;char b;double c;//4+1+3+8=16};union A{int a;char b;char c[5];struct B d;}obj;//16int main(){printf("%d", sizeof(obj));system("pause");return 0;}
所以结果为16

此结构空间要大到足够容纳最"宽"的成员;”是指其必须符合所有成员的自身对齐方式。

#include<stdio.h>#include<stdlib.h>union A{int a;char b;char c[5];}obj;int main(){printf("%d", sizeof(obj));system("pause");return 0;}
这个结果却是8,虽然此结构空间要大到足够容纳最"宽"的成员;,而最宽的成员一共是8个字节,然而成员自身还要对齐int也要自身对齐即为8个字节。

位段:

位段中如果前一个足够容纳后一个则后一个存放入前一个,如果前一个不足够容纳后一个,则后一个重新开辟。

#include<stdio.h>#include<stdlib.h>struct A{unsigned int b : 7;unsigned int c : 16;unsigned int x : 28;}obj;int main(){printf("%d", sizeof(obj));system("pause");return 0;}

答案是8,

#include<stdlib.h>struct A{unsigned int a : 4;unsigned int b : 7;unsigned int c ;unsigned int x : 28;}obj;int main(){printf("%d", sizeof(obj));system("pause");return 0;}

此时结果为12个字节。

2 0
原创粉丝点击