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

来源:互联网 发布:centos升级内核 编辑:程序博客网 时间:2024/05/20 23:31

结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。
先来声明一个结构体:

struct tag{ member-list;}variable-list; 

在声明结构的时候,可以不完全声明:

struct {    int a;    int b;    char c;}x;
struct {    int a;    float b;    char c;}a[15],*p;

下面这个结构体声明就是错误的声明:

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

举一个例子来说明结构体的使用:

struct Stu{    char name[20];    int age;    char sex[5];    char id[20];}n = { "zhangs", 20 , "male", "153515" };void main(){    printf("%s,%d,%s,%s", n.name, n.age,n.sex, n.id);    system("pause");}

“n = { “zhangs”, 20 , “male”, “153515” }; ” 这一步初始化了结构体变量,还可以这样初始化结构体变量:

struct Stu{    char name[20];    int age;    char sex[5];    char id[20];};struct Stu s = {"zhangs", 20 , "male", "153515"};

在输出结果时我们用了(.)符号完成了对结构体的访问,(.)操作符仅接受两个操作数。

现在已经掌握了结构体的基本使用,接下来我们讨论如何计算结构体的大小:
计算结构体的大小时要考虑到内存对齐问题。
结构体的内存对齐规则:

  1. 第一个成员在与结构体变量偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
    VS中默认的值为8
    Linux中的默认值为4
  3. 结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐
    数)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍
    处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整
    数倍。
struct S3{    double d;    char c;    int i;};//大小为16,最大对齐数为4struct S4{    char c1;    struct S3 s3;    double d;};//大小为32,最大对齐数8struct S5{    struct S4 s4;    int c3;};void main(){    printf("%d\n", sizeof(struct S3));    printf("%d\n", sizeof(struct S4));    printf("%d", sizeof(struct S5));    system("pause");}

 先来计算S3的大小,double和char 的大小为9,而最大对齐数int为4,(第一个成员也有对齐数,但是不需要对齐,不考虑对齐数),结构体大小要为最大对齐数整数倍,所以sizeof(S3) = 8+1+3+4=16.
 同理,S4大小为1+16+7+8=32.
S5大小是32+4吗?
答案是:不是。
  不是说不考虑第一个成员对齐数吗?
  这是因为结构体S5中嵌套了结构体S4,结构体S5的最大对齐数就是 结构体内的结构体S4 的最大对齐数8,36必须对齐到最大对齐的整数倍40,所以结果就是40。
  
为什么要存在内存对齐?
 1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能
在某些地址处取某些特定类型的数据,否则抛出硬件异常。
 2. 性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的
内存访问仅需要一次访问 。

位段
C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”(bitfield)。利用位段能够用较少的位数存储数据。
位段与结构体的不同:
 1.位段的成员必须是 int、unsigned int 或signed int 。
 2.位段的成员名后边有一个冒号和一个数字。
比如:

struct A{ int _a:2; int _b:5; int _c:10; int _d:30;}; 

那么位段的大小应该如何计算:
在32位平台下位段的最大数目为32,所以下例中int可存放 最大数目为32。

struct A{ int _a:2;  int _b:5;  int _c:10;  int _d:30;};void main(){     printf("%d", sizeof(struct A));     system("pause");}

这里写图片描述

位段不会像结构体那样浪费空间,它会连续存放,如果剩余空间不够存放,将开辟一个新的int来存放。
所以答案是8.
与结构相比,位段可以达到同样的效果,但是位段可以节省空间,但是有跨平台的问题存在(位段中最大数目会因平台不同而不同)。

枚举
先定义一个枚举

enum Day//星期{ Mon, Tues, Wed, Thur, Fri, Sat, Sun}; 

{}中的内容是枚举类型的可能取值,也叫 枚举常量 。这些可能取值都是有值的,默认从0
开始,一次递增1,当然在定义的时候也可以赋初值。
我们可以使用 #define 定义常量,为什么非要使用枚举?
枚举的优点:
 1. 增加代码的可读性和可维护性
 2. 很#define定义的标识符比较枚举有类型检查,更加严谨。
 3. 防止了命名污染(封装)
 4.便于调试
 5.使用方便,一次可以定义多个常量。
联合体
联合也是一种特殊的自定义类型
这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合
也叫共用体)。
声明一个联合体:

union Un{ char c; int i;}; 

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成
员的大小(因为联合至少得有能力保存最大的那个成员)。那么如何计算联合体的大小?
  联合的大小至少是最大成员的大小。
  当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数
倍。

union Un1{    char c[5];    int i;};union Un2{    short c[7];    int i;};void main(){    printf("%d\n", sizeof(union Un1));    printf("%d\n", sizeof(union Un2));    system("pause");}

在Un1中,char的大小为5,联合体大小要为最大对齐数的整数倍,所以Un1大小为8.
同理,Un2中,short大小为14,联合体大小为16.

介绍就到这里,这些自定义类型要经常使用,使代码更加简洁,易读。

阅读全文
0 0