首页 > 其他分享 >结构体,枚举,联合体

结构体,枚举,联合体

时间:2022-10-18 22:03:07浏览次数:52  
标签:位段 struct int 联合体 char 枚举 对齐 结构

为什么有自定义类型?

     C语言中的数据类型有int,float,double,short,char等,但是对于一些复杂的结构体我们还是不能用我们已有的类型来进行定义。比如说你想要描述一个人,你可能需要描述身高,电话,肤色,住址,工作等特征,所以我们可以自定义一个类型,类型中包含很多我们需要的特征。比如说:结构体类型,枚举类型,联合类型。

1.结构是一些值的集合,这些值成为成员变量,结构的每个成员可以是不同类型的变量。可以是整型,浮点型,函数,结构体

struct  name

{

    成员变量; 

}变量;

如:

  • struct 为结构体关键字    Stu 为结构体标签   struct  Stu 为结构体类型(可以类比于int)

        struct Stu

        {

            //    成员变量

             char  name[20];

             short  age;

             char tele[12];

             char  sex[5];

          }s1,s2,s3;//s1,s2,s3是三个全局的结构体变量

        int main()

        {

            struct Stu s;//s为局部变量

             return 0;

          }

  • 另一种方式

    typedef  struct Stu

        {

            //    成员变量

             char  name[20];

             short  age;

             char tele[12];

             char  sex[5];

          }Stu;(在此处Stu是类型不是变量)

此句话的意思就是说我可以给struct Stu 起另一个名字叫做Stu。在主函数中,定义一个结构变量就可以写成Stu n;或者struct Stu n;

结构体在定义的时候,是不能结构体中包含一个结构体的,但是可以包含一个结构体的地址。

比如:struct node

    {

        int a;

        struct node* su;

    }

2.在结构体中包含另一个结构体的时候,在初始化的时候,结构体要用大括号括起来。

如下:

结构体,枚举,联合体_位段

使用两种不同的访问成员的方式打印:

printf1和printf2哪个更好些?

首选printf2,因为函数传参的时候,参数是需要压栈的。如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能下降。

结构体,枚举,联合体_嵌套_02

3.结构体内存对齐


结构体对齐规则:

1.第一个成员在与结构体变量偏移量为0的地址处。

2.其他成员变量要对齐到对齐数的整数倍的地址处。

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

VS中默认的值为8(gcc编译器是没有对齐数的)

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

4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

为什么存在内存对齐?

1.平台原因(移植原因):不是所有的硬件平台都能访问任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2.性能原因:数据结构(尤其是栈)应该尽可能在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问金需要一次访问。

总体来说:结构体的内存对齐是拿空间换取时间的做法。

那么在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:

让占用空间小的变量尽量集中在一起。

#pragma pack(对齐数的值)  //设置默认对齐数

#pragma pack()       // 取消设置默认对齐数


4.offsetof(类型名,结构体成员)  可以计算结构体成员偏移量

  offsetof是一个宏,不是一个函数,所在头文件为#include <stddef.h>

等到学到宏的时候再加以补充


5.什么是位段?

位段的声明和结构是类似的,有两个不同:

  • 位段的成员必须是int,unsigned int或者 signed int  还可以是short, char
  • 位段的成员名后面有一个冒号和一个数字。

比如:struct A

    {

        int _a:2;

        int _b:5;

        int _c:10;

        int _d:30;

    };

a本来是占4个字节的,但是他用不了那么多空间,只用给他留2个空间就够了。所以位段的作用可以理解成是为了节省空间。

A就是一个位段类型,一个特殊的结构体类型。

位段的内存分配:

1.位段的成员必须是int,unsigned int或者 signed int  还可以是short(属于整型家族)

2.位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的。

3.位段设计很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。


6.枚举:顾名思义,就是一一列举的意思。

枚举的定义

enum Day

{

    //枚举的可能取值:枚举常量

//默认的初值为0,1,2,往后依次增加1。但是有时默认的值并不是我们想要的值,我们可以这样写:Mnotallow=2,这样是给常量赋初值。

    Mon, //0

    Tues, //1

    Wed,  //2

    Thur, //3

    Fri,  //4

    Sat, //5

    Sun  //6

};

int main()

{

    enum Day c=Mon;

    return 0;

}

为什么使用枚举?

我们可以使用#define定义常量,为什么非要使用枚举?枚举的优点:

1.增加代码的可读性和可维护性

2.和#define定义的表示符比较,枚举有类型检查,更加严谨

3.防止了命名污染(封装)

4.便于测试

5.使用方便,一次可以定义多个常量


7.联合(共用体)

union Un

{

  char c;

  int i;

}

 int main()

{

    union Un u;

    printf("%d\n",sizeof(u)); //4

    printf("%p\n",&u);        //O0F1F90C

    printf("%p\n",&(u.c));    //O0F1F90C

    printf("%p\n",&(u.i));    //O0F1F90C

}

可以观察到u,u.c,u.i他们三者共用一块空间,所以就要求不能同时使用联合体里面的成员。


8.存储的大小端字节序问题

一个16进制数字

int a=0x00000001

低地址……………………………………>高地址

……[][][][][][][00][00][00][01][][][][][]……  大端字节存储模式

……[][][][][][][01][00][00][00][][][][][]……  小端字节存储模式

讨论一个数据,放在内存中的存放的字节顺序

我们在写程序判断到底是大端还是小端的存储方式的时候,我们可以比较第一个字节里面的数字,如果第一个字节内的数字是1,那么就是小端存储。

int main()

{

    int a=1;

    (char*) &a;

    if((*(char*)&a)==1)  //此处借助一个char*的强制类型转化,因为转换成char类型后,可以访问一个字节的长度。

    {

        printf("存储方式为小端字节序存储模式");

    }

    else

    {

        printf("存储方式为大端字节序存储模式");

    }

    return 0;

}

同时也可以用联合体的方式来编写代码

联合大小的计算:

  • 联合的大小至少是最大成员的大小。
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

比如:union Un()

    int a;   //4 默认对齐数是8   ,所以4和8相比取4,

    char arr[5];  //  1,默认的对齐数8,  ,1和8相比取1,综合对齐数应该是4,   数组虽然是占用了5个空间,但是他还是要满足是4的倍数,所以最终的值取8.

};

int main()

{

    union Un u;

    printf("%d\n",sizeof(u)); //8

}


























标签:位段,struct,int,联合体,char,枚举,对齐,结构
From: https://blog.51cto.com/u_15760583/5768247

相关文章

  • Chap4 循环结构 第三小组 学习心得
             什么是循环结构? 循环结构是编程中必不可少的一个组成部分。通常可以和分支结构和顺序结构组成各种不同的程序。它有三种不同的表达方式:(1)w......
  • 06 数组与广义表 | 数据结构与算法
    1.数组1.数组的定义数组:数组是一组偶对(下标值,数据元素值)的集合。在数组中,对于一组有意义的下标,都存在一个与其对应的值。一维数组对应着一个下标值,二维数组对应着......
  • 数据结构——————排序算法代码实现(未完待续......)
    排序算法插入排序折半插入排序希尔排序冒泡排序快速排序简单选择排序堆排序归并排序(未完成)基数排序(未完成)#include<bits/stdc++.h>usingnamespacestd;constintMAXN......
  • 数据结构作业(2018/10/10)
    1.基本的a+b(+-*/%)#include<bits/stdc++.h>usingnamespacestd;intmain(){inta,b;charch;intans;scanf("%d%d%c",&a,&b,&ch);......
  • 链表实现队列——————数据结构作业
    作业code2:-仿照作业code1的功能,将课本上链表的实现队列能完整实现-需要通过main函数调用并能进行友好的人机交互输入​​作业code1​​链表实现队列的代码:#include<bits/......
  • 数据结构作业的代码——————栈的顺序实现
    作业code1:将上课给的顺序表形式实现栈的程序补充(代码已发给大家):实现通过键盘进行插入实现通过键盘进行删除良好的人机交互发的代码:#include<stdio.h>#include<malloc.h>t......
  • 思考问题的结构化
    最近发现工作电脑的键盘不灵光,今天上午来到一家维修店换键盘。在等待的过程中,看了下手机里截图的《金字塔原理》概要信息,这里几次提到了机构化,百度了下,解释如下:“所谓结构......
  • 矩阵还原——————数据结构作业
    /*给定一个一维数组,将其转化为对称矩阵(关于主对角线对称)*/#include<stdio.h>#include<string.h>constintMAXN=1e3;intmat[MAXN][MAXN];inta[MAXN];in......
  • 数据结构作业的代码——————栈的链式实现
    作业code2:仿照作业​​code1​​的功能,将课本上链表的实现栈的功能完整实现需要通过main函数调用并能进行友好的人机交互输入#include<bits/stdc++.h>#define#define#defin......
  • C语言零基础入门-结构体-01
    C语言零基础入门-结构体-01这节课的主要内容:1,什么是结构体。2,结构体的定义以及使用。1.什么是结构体这个问题就变得有意思了,为什么呢?因为他可以与我们之前的学习紧密相关了......