C语言中的数据封装特性

1、在C语言中基础数据封装主要有结构体(struct)、联合体(union)、枚举类型(enum)

  1、定义:

    结构体:是由一些具有相同类型、或者不同类型的数据组成的数据集合;

    联合体:在需要将不同的数据类型储存在同一段内存单元中。也是说覆盖技术,几个变量相互覆盖。这些不同类型变量存放在同一段内存结构。

        具有这种结构的数据类型,被称作联合体。

  2、结构数据的长度区别

    结构体类型数据长度:一个结构体变量的长度是各个成员长度之和

    联合体类型数据长度:一个联合体变量的长度等于成员中最长的那个;(存在数据对齐)

  3、结构中元素内存分配情况

    结构体:结构体名是结构体第一个地址,也就是首成员相对第一地址的偏移量为0,以后每个数据成员按照指定的偏移地址偏移;

    联合体:联合体中数据成员完成对齐之后,按照分配内存空间最大的成员存储数据;

  4、使用程序说明:

// 测试程序
#include <stdio.h>

// 定义一个学生的结构体
typedef struct student{
    int num;    // 4
    char name[64]; // 64字节
    char name1;    // 1字节
    double hight;  // 8字节
     float f;       // 4字节
    int age;       // 4字节   // 排序时候,存在数据对齐,不是4+64+1+8+4+4 
}stu;
// 定义一个联合体classes
typedef union classes  // 不是class类
{
    char name[51];    // 51字节
    int age;       // 4字节大小
    double height; // 8字节
}classes;

void main()
{
    stu s;
    classes u;
    // 打印常见的数据类型占用内存的大小
    printf("sizeof double is %d\n",sizeof(double));
    printf("sizeof int is %d\n",sizeof(int));
    printf("sizeof is %d\n",sizeof(float));
    // 结构体stu占用的内存大小 
    printf("sizeof struct is :%d\n",sizeof(s));
    // 打印结构体成员地址
    printf("address struct stu:%x\n",&s);
    printf("address struct stu.num:%x\n",&s.num);
    printf("address struct stu.name[64]:%x\n",(s.name));
    printf("address struct stu.name1:%x\n",&(s.name1));
    printf("address struct stu.f:%x\n",&(s.f));
    printf("address struct stu.gae:%x\n",&(s.age));
    
    // 打印联合体成员地址
    printf("sizeof union is :%d\n",sizeof(u));
    printf("address union u:%x\n",&u.name);
    printf("address union u:%x\n",&u.age);
    printf("address union u:%x\n",&u.height);
    
    printf("hello world\n");
    getchar();
}

  输出结果:

sizeof double is 8
sizeof int is 4
sizeof is 4
// 结构体大小
sizeof struct is :88
// 结构体地址
address struct stu:113fbd4
address struct stu.num:113fbd4
address struct stu.name[64]:113fbd8
address struct stu.name1:113fc18
address struct stu.f:113fc24
address struct stu.gae:113fc28
// 联合体大小
sizeof union is :56
// 联合体地址
address union u:113fb94
address union u:113fb94
address union u:113fb94
hello world

 

2、关键修饰符static、const、volatile

  static:

    1、修饰局部变量:

      1、用于延长变量的生命周期:相对于普通局部变量,是保存在栈上,函数一旦退出或者结束,变量就会被释放掉;二次访问的会出现新的初始值;使用static关键字修饰后的变量,该变量始终保存在静态的数据段中;直到整个程序退出,该变量才被释放;

      2、局部变量的静态化:局部变量保存在栈上,被修饰后,局部变量保存在静态的数据段;    

    2、修饰全局变量:

      主要防止重命名,主要用于多文件编程,也就是限制作用域;被修饰函数的作用域限制在当前文件;

    3、修饰全局函数名称:

      限制函数名称重命名,限制函数只在该文件的访问权限;

  const:

    1、对于C语言编译器,修饰的变量的表面是只读属性,但是只是建议性的,并不具备强制性;也就是说const int a =20;修饰的变量a编译器建议不修改,但是可以使用指针修改a的值;

    2、对于C++编译器,const修饰的变量就是只读属性,不可以修改,C++语法相对于C语法更严谨;

  volatile:

    表明该变量可能被外界修改,不需要编译器做优化;可能修饰寄存器相关、中断相关、多线程相关;

    对于volatile关机键字可以从反汇编角度看:

// 对于同一段代码
int func1(int* p)
{
    return (*p == *p);  
}

int func2(volatile int* p)
{
    return (*p==*p);      
}

  编译以反汇编后:可以看出func1中直接返回结果,func2中取了两次值,并比较寄存器中的值cmp(使用的编译器可能存在差异,结果稍微不同)

arm-none-linux-gnueabi-gcc -c test.c -o test.o
arm-none-linux-gnueabi-objdump -D test.o // 显示在屏幕上,如下图

 

 

 3、define宏定义一个模块

#define   myStruct   (struct stu*)
typedef     struct stu*    myS;

myStruct stu1, stu2;    --->struct stu* stu1, stu2;
myS   stu1, stu2;       --->struct stu* stu1, *stu2;

    从上面列子可以看出来,define和typedef之间存在这样的差异;

 

 

 

 

 

  

posted @ 2020-11-27 10:22  笑不出花的旦旦  阅读(643)  评论(0)    收藏  举报