打印
[牛人杂谈]

谈谈C语言结构体struct、公用体union空间占用

[复制链接]
1779|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhuomuniao110|  楼主 | 2016-4-30 20:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include<stdio.h>
union union_data0{
        int a ;//本身占用4个字节
        char b ;//本身占用1个字节
        int c ;
};
union union_data1{
        short a;//本身占用2个字节
        char b[13];//本身占用13个字节
        int c ;//本身占用4个字节
};
struct struct_data{
        int a ;//int本身占用4个字节,偏移量为0
        char b ;//char本身占用1个字节,偏移量为4
        int  c ;//1.暂时偏移量为5,编译器会判断出5不是4的整数倍,会在b的后面填充3个字节,最后c的偏移量为8,使得c的偏移量为c本身大小的整数倍;2.现在整个结构体大小暂时为12,编译器会判断12是不是其最大成员的整数倍,会在c末尾填充为整数倍,最后得出结果为12
};
int main(int argv,char* args[])
{
        printf("%lu\n",sizeof(union union_data0)) ;
        printf("%lu\n",sizeof(union union_data1));
        printf("%lu\n",sizeof(struct struct_data)) ;
        return 0;
}
结果:
[xx@localhost cdemo]$ gcc union_struct_space.c -o union_struct_space.out[xx@localhost cdemo]$ ./union_struct_space.out 41216

沙发
zhuomuniao110|  楼主 | 2016-4-30 20:50 | 只看该作者
结构体类型说明的一般形式为:
    struct 结构体标识名
    {
      类型名1  结构成员名表1
      类型名2  结构成员名表2
      ...
      类型名n  结构成员名表n
    };
  其中 struct 是关键字。“结构体标识名”和“结构成员名”是用户定义的标识符,其中“结构体标识名”是可选项,在说明中可以不出现。每个“结构成员名表”中都可以含有多个同类型的成员名,它们之间用逗号隔开。结构体中的成员名可以和程序中的其他变量同名;不同结构体中的成员也可以同名。注意:结构体说明同样要以分号(;)结尾。
    struct date
    {int year, month, day;};
  结构体类型说明中的“类型名”,不仅可以是简单数据类型,也可以是结构体类型。当结构体说明中又包含结构体时,成为结构体的嵌套。如下:
    struct student
    {
      char name[12];
      char sex;
      struct date birthday;
      float sc[4];
    };
  ANSI C 标准规定结构体至少允许嵌套15层,允许内嵌结构体成员的名字与外层成员的名字相同。
  结构体类型的说明只是列出了该结构的组成情况,标志着这种类型的结构“模式”已经存在,编译程序并没有因此而分配任何存储空间。真正占有存储空间的仍是具有相应结构体类型的变量、数组以及动态开辟的存储单元。因此,在使用结构体变量、数组或指针变量前,必须先对这些变量、数组或指针变量进行定义。

使用特权

评论回复
板凳
zhuomuniao110|  楼主 | 2016-4-30 21:08 | 只看该作者
结构体类型的变量、数组和指针变量的定义  可以用以下四种方式定义结构体类型的变量、数组和指针变量:
  (1)紧跟在结构体类型说明之后进行定义。例如:
    struct student
    {
      char name[12];
      char sex;
      struct date birthday;
      float sc[4];
    } std, pers[3], *pstd;
  此处,在说明结构体类型 struct student 的同时,定义了一个结构体变量 std、有3个变量的结构体数组 pers 和基类型为结构体类型的指针变量 pstd。
  (2)在说明一个无名结构体类型的同时,直接进行定义。如:上述定义的结构体中可以把 student 省略,写成:
    struct
    {...
    } std, pers[3], *pstd;
  这种方式与前一种的区别仅仅是省略了结构体标识名,通常用在不需要再次定义此类型结构体变量的情况。
  (3)先说明结构体类型,再单独进行变量定义。如:
    struct student
    {...
    };
    struct student std, pers[3], pstd;
  此处,先说明了结构体类型 struct student,再由一条单独的语句定义变量 std、数组 pers 和指针变量 pstd。使用这种定义方式应注意:关键字 struct 必须和结构体标识名 student 共同说明结构体类型。
  (4)使用 typedef 说明一个结构体类型名,再用新类型名来定义变量。如:
    typedef struct
    {
      char name[12];
      char sex;
      struct date birthday;
      float sc[4];
    } STREC;
    STREC std, pers[3], *pstd;
  STREC 是一个具体的结构体类型名,它能够唯一地标识这种结构体类型。因此,它可以用来定义变量,如同使用 int 、char  一样,不可再写关键字 struct。

使用特权

评论回复
地板
zhuomuniao110|  楼主 | 2016-4-30 21:10 | 只看该作者
给结构体变量、数组赋初值  和一般变量、数组一样,结构体变量和数组也可以在定义的同时赋初值。
   给结构体变量赋初值  所赋初值放在一对花括号中,如:
    struct student
    {
      char name[12];
      char sex;
      struct date birthday;
      float sc[4];
    } std = {"Li Ming", ‘M’, 1997, 5, 10, 88.0, 76.0, 85.5, 90.0};
  赋初值后,变量 std 内容如图所示:
  name  sex    birthday  sc[0]  sc[1]  sc[2]  sc[3]
         year   month  day
Li Ming
M
1997
5
10
88.0
76.0
85.5
90.0
  对结构体变量赋值时,C 编译程序按每个成员在结构中的顺序一一对应赋初值,不允许跳过前面的成员给后面的成员赋初值。但可以只给前面的若干成员赋初值,对后面未赋初值的成员,系统将自动为数值型和字符型数据赋初值0。
   给结构体数组赋初值  由于数组中每个元素都是一个结构体,因此通常将其成员的值依次放在一对花括号中,以便区分各个元素。
    struct bookcard
    {
      char num[5];
      float money;
    } bk[3] = { {"NO.1", 35.5}, {"NO.2", 25.0}, {"NO.3", 66.7} };
         /* bk[0]      bk[1]      bk[2]  */
  也可以通过这种赋初值的方式,隐含确定结构体数组的大小。即:由编译程序根据所赋初值的成员个数决定数组元素的个数。以下是一个给二维数组赋初值的例子:
    struct
    {
      char ch;
      int i;
      float x;
    } arr[2][3] = {
             { {"a", 1, 3.0e10}, {"a", 2, 4.0e10}, {"a", 3, 5.0e10} },  /*第一行*/
             { {"b", 1, 6.0e10}, {"b", 2, 7.0e10}, {"b", 3, 8.0e10} }  /*第二行*/
           };
  根据花括号的嵌套关系,可以清楚的分辨出所赋初值与数组元素一一对应的关系。
    相同类型结构体变量之间的整体赋值  ANSI C 标准允许相同类型的结构体变量之间进行整体赋值。如:
    struct
    {
      char name[10];
      int num;
    } per1, per2 = {"Jhon", 46};
  执行赋值语句:per1 = per2; 则 per2 中每个成员的值都赋给了 per1 中对应的同名成员。这种赋值方法必须要保证赋值号两边结构体变量的类型相同。

使用特权

评论回复
5
zhuomuniao110|  楼主 | 2016-4-30 21:12 | 只看该作者
机构体(struct)

  计算公式: space(struct)=最后一个成员的偏移量+最后一个成员数据类型的大小+末尾填充字节数(公式1)

    原则:
1.每个成员的偏移量要整除本身的大小,若不能整除,在其前的成员的后面字节填充。
2.最后的结构的大小要整除最大成员的大小,若不能整除,在最后的成员的后面字节填充。 

公用体(union),是个结构,他的所有的成员相对于基地址的偏移量都为0,他的结构空间要大到足够容纳最“宽”的成员,并且对齐方式要适合于所有公用体中所有类型的成员。也就是说

上面的公式(公式1)也是适用的。

  计算公式:  space(union)=max(成员的偏移量)+某位填充字节

  简单的原则:max(成员的偏移量)要整除各个成员,若不能整除,在最后的成员的后面字节填充。

注:此处偏移量:机构中某个成员的实际地址离其结构的首地址的距离。

引出问题:
1.为什么要字节对齐?
答:是为了能让计算机快速读写,是一种以时间换取空间的方式。

使用特权

评论回复
6
huangcunxiake| | 2016-4-30 22:16 | 只看该作者
struct struct_data{
        int a ;//int本身占用4个字节,偏移量为0
        char b ;//char本身占用1个字节,偏移量为4
        int  c ;//1.暂时偏移量为5,编译器会判断出5不是4的整数倍,会在b的后面填充3个字节,最后c的偏移量为8,使得c的偏移量为c本身大小的整数倍;2.现在整个结构体大小暂时为12,编译器会判断12是不是其最大成员的整数倍,会在c末尾填充为整数倍,最后得出结果为12
};

使用特权

评论回复
7
chunk| | 2016-5-1 08:17 | 只看该作者
int  c ;//1.暂时偏移量为5,编译器会判断出5不是4的整数倍,会在b的后面填充3个字节,最后c的偏移量为8,使得c的偏移量为c本身大小的整数倍;2.现在整个结构体大小暂时为12,编译器会判断12是不是其最大成员的整数倍,会在c末尾填充为整数倍,最后得出结果为12


这说法具有普遍适用性吗?你只用过32bit RISC处理器吧?在这个处理器上int类型是32bit的,并且只能在4字节地址边界上访问对吧?

使用特权

评论回复
8
疯小子| | 2016-5-1 09:11 | 只看该作者
太复杂

使用特权

评论回复
9
cowboy2014| | 2016-5-4 22:17 | 只看该作者
zhuomuniao110 发表于 2016-4-30 20:50
结构体类型说明的一般形式为:
    struct 结构体标识名
    {

结构体在内存当中是连续存放的而联合体有可能不是

使用特权

评论回复
10
zhuomuniao110|  楼主 | 2016-5-8 19:30 | 只看该作者
cowboy2014 发表于 2016-5-4 22:17
结构体在内存当中是连续存放的而联合体有可能不是

你这个话不科学,结构体是连续存放,而联合体是叠加形式的平行存放。

使用特权

评论回复
11
zhuomuniao110|  楼主 | 2016-5-8 19:44 | 只看该作者
cowboy2014 发表于 2016-5-4 22:17
结构体在内存当中是连续存放的而联合体有可能不是

实际上就是联合体给同一个内存地址分段起不同的名字而已。

使用特权

评论回复
12
zhuomuniao110|  楼主 | 2016-5-8 19:51 | 只看该作者

哈哈,这几个点精通了,就该是高手了。

使用特权

评论回复
13
zhuomuniao110|  楼主 | 2016-5-8 19:51 | 只看该作者
chunk 发表于 2016-5-1 08:17
这说法具有普遍适用性吗?你只用过32bit RISC处理器吧?在这个处理器上int类型是32bit的,并且只能在4字 ...

好像是的,不过可以通过sizeof控制吧。

使用特权

评论回复
14
zhuotuzi| | 2016-5-8 23:09 | 只看该作者
ANSI C 标准规定结构体至少允许嵌套15层,允许内嵌结构体成员的名字与外层成员的名字相同。这么多层?

使用特权

评论回复
15
capturesthe| | 2016-5-9 17:54 | 只看该作者
这个公用体在硬件编程里面主要是怎么用呢

使用特权

评论回复
16
gejigeji521| | 2016-5-9 23:34 | 只看该作者
结构体类型的说明只是列出了该结构的组成情况,标志着这种类型的结构“模式”已经存在,编译程序并没有因此而分配任何存储空间。

使用特权

评论回复
17
zhuomuniao110|  楼主 | 2016-5-11 21:44 | 只看该作者
嵌套十五层已经够了,实际上8层都用不完了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

205

主题

3349

帖子

10

粉丝