嵌入式学习一阶段——C语言:结构体

sizeof()

sizeof 求字节运算符
    sizeof x
    sizeof(x)
    用来求一个对象或类型所占字节数的运算符
        x可以是一个对象,也可以是一个类型
sizeof(x): 求x所占的内存的字节数
    x可以是一个对象(变量,数组......)也可以是一个类型
        x可以不存在,只要typeof(x)可以确定就ok

sizeof(x) : 先求x的类型,然后再求该类型所占的字节数

结构体

问题的一个引入

”建模“ : 建立模型
    为什么需要建模??
问题域(问题空间):
    跟问题本身相关一些因素,元素,条件等等这些
        分析问题,需求,目标
        算法思路(解决问题的一些步骤)
解决方案域(解空间):
    与具体的解决问题的方式,方法相关的一些因素,条件
        如:
            数学---》数学方法(公式,方程,。。。。。)
            C语言 ---> 算法的模型,存储类型,变量,语法....
​
问题域 -----> 解决方案域
    把问题域里面的一些元素转换成解决方案域的元素
    这个过程,建模
​
”人“ : 在解决方案域(C)用什么来描述的???
​
现实生活中的物体需要抽象成计算机语言中的数据类型(对象)
​
物体的属性:
        学生:
            学号 ----> int num
            姓名 ----> char name[32];
            性别 ----> char gender;  //'1''0'
            年龄 ----> int age;
            地址 ----> char addr[32];
            .....
        ====> 把这些物品的属性组合到一个数据类型当中去,用来表示”学生“
​
C语言允许程序员定义自己的组合类型:
        结构体
        共用体
        枚举

结构体 : 自定义的一种组合类型

定义:

struct 结构体名
{
    成员类型1 成员名1;
    成员类型2 成员名2;
    .......
    成员类型n 成员名n;
};
结构体类型是由多个成员构成的,而且每一个成员都有自己的类型(只要是合法的类型就可以),
当然不同的成员,它的类型也是可以相同的,但是成员名不能一样。
​
”结构体名“ : 符合C语言关于标识符的规定
    struct 结构体 => 你定义的新类型的名字。
    如:
        struct student
        {};
​
struct student zyz;
​
"成员类型1" 、 "成员类型2" 、 。。。。。 "成员类型n":
        只要是C语言中合法的类型都可以(基本类型,构造类型,指针......)
​
"成员名1"、"成员名2"、。。。。。。、"成员名n":
        要符合C语言中标识符的规定就可以了
​
例子:
        struct student
        {
            int num;
            char name[32];
            char gender;
            int age;
            float score;
        };
​
上面定义了一个新的类型 : struct student
        并且这个新的类型里面包括:num name gender age score这些成员变量
        如何定义一个新类型的变量:
            变量的定义:
                变量的类型 变量名= {初始值};
struct student zyz;
                zyz 里面就会有一个int类型的num.......
​
那么这些成员变量在内存当中是如何分布的呢??

结构体成员的内存布局

(1)、结构体类型所占空间是各成员变量所占的空间之和
(2)、结构体内各成员变量按他们所定义时出现的次序,依次保存

结构体变量的引用

结构体的内部的成员变量的引用 (1)、 . 域操作符:取某个子成员变量 结构体变量名.成员变量名 =>取结构体变量内部的成员变量 例子: struct student s; s.num; s.age; ...... 引用成员变量和普通变量一样,有左值,右值 s.age = 20; int b = s.age;

scanf("%d",&(s.age));
​
//struct student *p = malloc(sizeof(*p));
    struct student *p = malloc(sizeof(struct student));
​
p 就指向struct student 一个对象
        *p => 指向的那个对象(结构体变量)。
            (*p).age;
            (*p).num;
    (*结构体指针).成员变量

(2)、-> 结构体指针->成员变量 如: p->age; p->num; p->name; ->引用成员变量和引用普通变量是一样的,有左值,也有右值 p->num = 20; int b = p->num;

初始化结构体方法

定义结构体变量时就赋初值
结构体的初始化就要使用{}
//日期
struct date
{
    int y,m,d;
};
struct student
{
    int num;
    char name[32];
    strcut date birthday;
    float score;
};
​
(1)、按定义时的顺序依次初始化各成员变量,用逗号分开;
    struct student s = {
        1,
        "zhoushuaige",
        {1999,01,03},
        100
    };
(2)、不按顺序,.成员变量名 = 值;
    struct student s = {
        .name = "zhangsan",
        .birthday = {2000,01,03},
    };
(3)、结构体数组的初始化
    a、按照数组元素的顺序依次初始化
       struct student class[3] = {
            //class[0]
            {
                .num = 1,
                .name = "lisi",
                .birthday = {2000,01,03},
                .score = 90
            },
            //class[1]
            {
                .num = 2,
                .name = "wangwu",
                .birthday = {2001,01,03},
                .score = 86
            },
            //class[2]
            {}
       };
    b、不按数组元素的顺序,[下标] =
        这种方式不同的编译器,情况或者限制都会不一样
        struct student class[3] =
        {
            [0] = {       //class[0]
                .num = 1,
                .name = "lisi",
                .birthday = {2000,01,03},
                .score = 90
            },
            [2] = {
.num = 2,
                .name = "wangwu",
                .birthday = {2001,01,03},
                .score = 86
            },
        };

共用体

union 共用体名
{
    成员类型1 成员变量1;
    成员类型2 成员变量2;
    .......
    成员类型n 成员变量n;
};
​
共用体与结构体最大的区别:
    结构体所占的内存大小是各成员变量之和;
    共用体所占的内存大小是各成员变量中最大的那个。
​
共用体的存储空间是各成员之间共用的。
同一个时刻只能用一个成员变量,为了节省 内存 才提出的  共用体 。
​
例子:
(1)、
    union test
    {
        int a;
        int b;
    };
    union test 占4个字节,成员变量a和b共用这四个字节
​
union test t;
    printf("%p\n",&t);
    printf("%p\n",&t.a);
    printf("%p\n",&t.b);
​
t.a = 5;
    printf("%d\n",t.b);
​
(2)、
    union test
    {
        char a;
        int b;
    };
    sizeof(union test) == 占4个字节 ??
​
union test t;
    printf("%p\n",&t);
    printf("%p\n",&t.a);
    printf("%p\n",&t.b);
​
t.a = 65;
    printf("%c\n",t.a);
​
大端模式 与 小端模式
        CPU 内部寄存器 是 按bit位 来存储信息的,
        但是 CPU内部寄存器的数量 是 非常有限的,所以
        我们经常需要把寄存器存储到 存储器(内存)当中去。
​
但是内存不是按 bit 来寻址的,按照字节编号(地址)来寻址
​
如果把寄存器的内容存储到内存当中去,那么
            内存的低地址到底是存在寄存器中的低字节还是高字节呢??
​
大端模式:
            存储器的低地址,存放寄存器的高字节。
        小端模式(小弟弟):
            存储器的低地址,存放寄存器的低字节。

练习: 1、你写一个代码,来验证一下 运行你代码的机器到底是小端模式还是大端模式??? union test { char a; int b; };

union test s;
            s.b = 1;
​
if(s.a)
            {
                小端
            }
            else
            {
                大端
            }
​
(3)、假设在32bit的小端模式的机器下运行,如下代码,请分析输出结果
    union test
    {
        char a;
        int b;
    };
     union test t;
     t.b = 255;
​
    t.b++;
     printf("%d\n",t.a);

枚举

把该类型变量所有的可能的值一一列举出来。
所以枚举类型一定可以列举的值,也就是说整数值
有些一些情况,一个变量的值,是在一定范围之内的
如:
    int weekday;   //星期几
            //1 2 3 4 5 6 7
    weekday = 1;
    weekday = 250;
​
    枚举语法:
        enum weekday
        {
            MON = 1024,
            TUE,
            WUE,
            THU,
            FRI,
            SAT = 2048,
            SUN
        };
        enum weekday w = MON;

构造类型: 结构体 共用体 枚举 数组 也是一个构造类型 int a[4]; //定义一个数组 //同时你也声明了一个新的类型, 像a这样子的类型

定义一个与a类型一样的变量b
    typeof(a) b;

typedef

typedef 是用来声明一个新的类型的
        用来声明一个新的类型名,来替换一个已经拥有的类型。 方便移植
​
语法:
    typedef 现有的类型名 新类型名
        =====> 新的类型名 就和 现有的类型名 类型一样
    
    typedef unsigned char uchar8;
        uchar8 a; 
    typedef unsigned int uint32;
          uint32 b;
​
    typedef struct student STU;
        STU s;
            ====>  struct student s;
​
    int NUM[100];  //定义了一个数组,名为NUM
        假如让你定义一个和NUM一样的类型变量a    
        typeof(NUM) a;
​
        typedef int[100] NUM_T;
            NUM_T a;
        
    void (*p)(int , float);   // p是什么呢??      //p是一个函数指针变量
​
    typedef void (*p)(int , float) ;   //p是什么??
                                    //p是一个类型,函数指针类型  //指向 返回void , 带 int,float的函数

字节对齐的问题

CPU 底层为了访问的效率出发,一般会要求,任何对象的地址是对齐。
 
    自然对齐:
        数据地址是数据长度的倍数。
            如:
                sizeof(int) = 4;
                int a;
                    &a 不是4的倍数,a就不是自然对齐
    n字节对齐
        地址是n的倍数(n一般是2的x次幂)
            4 - 字节对齐
            8 - 字节对齐
            。。。。。
    
结构体的每一个成员变量通常会有一个默认的对齐方式,成员变量
将按照(除非程序员有其他的对齐要求)默认的对齐方式是:自然对齐
    struct test
    {
        char a;         //a的地址必须是1的倍数
        int b;          //b的地址必须是4的倍数
    };
​
    sizeof(struct test) == 8
        a _ _ _ x x x x
​
在  32 bits x86 机器,编译:
    VC++
    C++ builder
    DMC
    gcc
​
对 
   a char(1)    一字节对齐
   a int (4)    四字节对齐
   a short (2)  两字节对齐
   a double (8) 8字节对齐   on windows
                    四字节对齐 on linux (除非 -malign-double 8字节对齐)
   a float (4)  4字节对齐
   a long (4)   4字节对齐
   a long long(8字节)  4字节对齐
   a long double(10字节) (具体对齐方式和你的 电脑 还有 编译器 还有 系统 有关)
 
   any pointer (四字节) 4字节对齐  (任何指针)
​
   对结构体按最大的原始类型的对齐方式
    struct test
    {
        char a;  //1
        short b; //2
        int c;   //4
    };
​
    struct test
    {
        char a;  //1
        int c;   //4
        short b; //2
    };
​
    对齐的方式,就会决定结构体是否会有空洞!!
练习
1、
struct MaxedDate
    {
        char Data1;
        short Date2;
        int Date3;
        char Date4;
    };
    sizeof(struct MAxedDate) === 12
​
2、
struct FindPad
{
    float x;
    char n[1];
};
sizeof(struct FindPad) == 8
​
3、
struct FindPadshort
{
    short x;
    char n[3];
};
sizeof(struct FindPadshort) == 6
​
4、
struct MixedDate
{
    char data1;
    short data2;
    int data3;
    char date4
};
​
struct test
{
    char s;
    struct MixedDate m;
}
​
sizeof(struct test) == 16


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值