自定义类型:联合体和枚举

简介: 联合体类型,联合体的大小计算,联合体的实际应用,练习:判断大小端,枚举类型,枚举类型的声明:枚举类型的优点,枚举类型的实际案例:

联合体类型

联合体的声明:

union 联合体名{

成员列表

}变量列表;

注意事项:

1、联合体所有成员共⽤同⼀块内存空间,它们的地址也相同

#include <stdio.h>
union Un
{
 char c;
 int i;
};
int main()
{
 union Un un = {0};
 printf("%p\n", &(un.i));
 printf("%p\n", &(un.c));
 printf("%p\n", &un);
 return 0;
}

2、给联合体其中一个成员赋值,其他成员的值也跟着变化

#include <stdio.h>
union Un
{
 char c;
 int i;
};
int main()
{
 union Un un = {0};
 un.i = 0x11223344;
 un.c = 0x55;
 printf("%x\n", un.i);
 return 0;
}


un.i在存中的变化:


当我们对un.c赋值0x55的时候,un.i的值发生了改变:


联合体的大小计算

计算规则:

联合体大小的计算规则与结构体大小的计算规则(内存对齐)有相似之处

1、联合的⼤⼩⾄少是最⼤成员的⼤⼩

2、联合体最⼤成员⼤⼩不是最⼤对⻬数的整数倍的时候,就要对⻬到最⼤对⻬数的整数倍

#include <stdio.h>
union Un1
{
 char c[5]; //5字节        1  8  1
 int i;     //4字节        4  8  4
};0
union Un2
{
 short c[7];//14字节       2  8  2
 int i;     //4字节        4  8  4
}; 
int main()
{
 printf("%d\n", sizeof(union Un1));
 printf("%d\n", sizeof(union Un2));
 return 0;
}

①Un1中最大成员大小为5,最大对齐数为4,所以联合体大小为8

②Un2中最大成员大小为14,最大对齐数为4,所以联合体大小为16


联合体的实际应用

       我们要搞⼀个活动,要上线⼀些礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。 每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息

图书:书名、作者、⻚数

杯⼦:设计

衬衫:设计、可选颜⾊、可选尺⼨

可以直接写出⼀下结构:

struct gift_list
{
//公共属性
int stock_number;//库存量
double price; //定价
int item_type;//商品类型
//特殊属性
char title[20];//书名
char author[20];//作者
int num_pages;//⻚数
char design[30];//设计
int colors;//颜⾊
int sizes;//尺⼨
};

  上述的结构其实设计的很简单,⽤起来也⽅便,但是结构的设计中包含了所有礼品的各种属性,这样使得结构体的⼤⼩偏⼤,浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息是常⽤的。⽐如:商品是图书,就不需要design、colors、sizes这些属性。 所以我们应当把公共属性单独写出来,剩余的属于各种商品本⾝的特殊属性放进联合体中:


/

#include <stdio.h>
struct gift_list
{ //通用属性
  int stock_number;//库存量
  double price;//定价
  int item_type;//商品类型
  //特殊属性
  union {
    struct
    {
      char title[20];//书名
      char author[20];//作者
      int num_pages;//页数
    }books;
    struct
    {
      char design[30];//设计
    }mug;
    struct {
      char design[30];//设计
      int colors;//颜色
      int sizes;//尺寸
    }shirt;
  }items;
};
int main()
{
  struct gift_list gl = {0};
  gl.stock_number = 100;
  gl.price = 25;
  gl.item_type = 2;
  gl.items.books = {"wode","nde",30};
  printf("%s,%s,%d", gl.items.books.title, gl.items.books.author, gl.items.books.num_pages);
  return 0;
}


练习:判断大小端

#include <stdio.h>
int check()
{
  int a = 1;
  return (*(char*)&a);
}
int main()
{
  int a = 1;
  if (check)
    printf("小端\n");
  else
    printf("大端\n");
  return 0;
}

利用联合体实现大小端的判断:

#include <stdio.h>
int check_sys()
{
  union
  {
    int i;
    char c;
  }un;
  un.i = 1;
  return un.c;
}
int main()
{
  if (check_sys() == 1)
    printf("小端\n");
  else
    printf("大端\n");
  return 0;
}


   当我们给un.i赋值给1后,小端机器在内存中的存储形式为01  00  00  00,然后此时联合体内的char c也要占用一个字节的空间覆盖了原来01所在的内存空间,此时返回un.c所在的内存空间发现原来的01变为现在的00,所以为小端机器。  

枚举类型

       枚举就是一一列举,它可以用来列举我们日常生活中常见的各种东西,比如性别里的男和女,颜色里的赤橙黄绿青蓝紫......

枚举类型的声明:

enum 类型名
{
枚举常量 (建议全部大写)
};
enum Sex//性别
{
 MALE,
 FEMALE,
 SECRET
};
enum Color//颜⾊
{
 RED,
 GREEN,
 BLUE
};

其中,enum Color和enum Sex叫做枚举类型,MALE、FEMALE等叫做枚举常量它们是枚举类型的可能取值我们打印一下它们看看:

#include <stdio.h>
enum Sex//性别
{
  MALE,
  FEMALE,
  SECRET
};
enum Color//颜⾊
{
  RED,
  GREEN,
  BLUE
};
int main()
{
  enum Sex sex = MALE;  //枚举类型的使用方式就是将枚举常量赋值给枚举类型的变量;
  printf("%d %d %d ", MALE, FEMALE, SECRET);
  return 0;
}


我们会发现打印结果为0 1 2,这是以为这些枚举常量都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。

枚举类型的优点

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


2、和#define定义的标识符⽐较枚举有类型检查,更加严谨。


3、便于调试,预处理阶段会删除 #define 定义的符号


4、使⽤⽅便,⼀次可以定义多个常量


5、枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使⽤

枚举类型的实际案例:

本案例取自本人的另一篇文:《贪吃蛇---C语言版本》

//贪吃蛇游戏中反应蛇移动方向的枚举类型
enum DIRECTION
{
    UP,            //向上
    DOWN,          //向下 
    LEFT,          //向左
    RIGHT          //向右
};
//定义反应游戏状态的枚举类型
enum GAME_STATUS
{
    OK,              //游戏正常运⾏
    KILL_BY_WALL,    //撞墙
    KILL_BY_SELF,    //自己撞到自己
    END_NOMAL        //正常结束(自己选择ESC结束游戏)
};
//利用switc判断ps->_Dir的不同方向
  switch (ps->_Dir)
  {
  case UP:
    //如果蛇是向上运动的,那么蛇运动的下一个结点的x轴坐标与蛇头保持一致,y轴坐标为蛇头y轴坐标减一,下面的就不一一写解释了
    pNext->x = ps->_pSnake->x;
    pNext->y = ps->_pSnake->y - 1;
    break;
  case DOWN:
    pNext->x = ps->_pSnake->x;
    pNext->y = ps->_pSnake->y + 1;
    break;
  case LEFT:
    pNext->x = ps->_pSnake->x - 2;
    pNext->y = ps->_pSnake->y;
    break;
  case RIGHT:
    pNext->x = ps->_pSnake->x + 2;
    pNext->y = ps->_pSnake->y;
    break;
  }

  与switch结合是目前我所见到的唯一一个对于枚举类型的使用案例,可能还会有其他的后续学习过程中会进行适当的补充......

相关文章
|
3月前
|
自然语言处理 IDE 开发工具
Xcode 26 beta (17A5241e) 发布 - Apple 平台 IDE
Xcode 26 beta (17A5241e) 发布 - Apple 平台 IDE
190 0
Xcode 26 beta (17A5241e) 发布 - Apple 平台 IDE
|
11月前
|
JavaScript 前端开发 中间件
探索后端技术:Node.js与Express框架的完美融合
【10月更文挑战第7天】 在当今数字化时代,Web应用已成为日常生活不可或缺的一部分。本文将深入探讨后端技术的两大重要角色——Node.js和Express框架,分析它们如何通过其独特的特性和优势,为现代Web开发提供强大支持。我们将从Node.js的非阻塞I/O和事件驱动机制,到Express框架的简洁路由和中间件特性,全面解析它们的工作原理及应用场景。此外,本文还将分享一些实际开发中的小技巧,帮助你更有效地利用这些技术构建高效、可扩展的Web应用。无论你是刚入门的新手,还是经验丰富的开发者,相信这篇文章都能为你带来新的启发和思考。
|
11月前
|
存储 数据可视化 API
API接口数据获取流程的细化
本文概述了API的基础知识、获取API访问权限的方法、编写代码调用API的步骤、数据处理与分析技巧以及数据安全与合规的重要性,并提供了社交媒体数据分析、天气预报应用和电商数据分析等API数据获取的应用实例,旨在帮助读者全面了解和实践API接口数据获取的流程。
|
监控 数据可视化 算法
三维可视化神器带来无限可能,原来三维场景也可以如此轻松实现
三维可视化神器带来无限可能,原来三维场景也可以如此轻松实现
245 1
三维可视化神器带来无限可能,原来三维场景也可以如此轻松实现
|
网络协议 算法 程序员
网络必修课:以太网报文格式详解
嗨,大家好!今天,我要带大家深入了解以太网报文格式,这是现代网络通信的重要基础。无论你是网络工程师、开发者,还是对技术感兴趣的朋友,这篇文章都将为你揭开以太网的神秘面纱,让你更好地理解和应用这一关键技术。准备好了吗?让我们开始吧!
502 4
|
消息中间件 Kafka API
Kafka - 图解生产者消息发送流程
Kafka - 图解生产者消息发送流程
375 0
|
消息中间件 网络协议 安全
基于网关服务治理的研究与实践(五)从开源网关到自研网关
在上一篇API网关介绍中,由于开源网关方案的不足,且目前没有能够同时兼容Http、Socket、WebSocket协议的开源网关,无法实现对业务请求的统一管控,对于服务治理整体方案略有不足;在当前背景下,产生了自研网关的想法,本篇文章详细记录了自研网关所做的技术研究内容。
2139 0
基于网关服务治理的研究与实践(五)从开源网关到自研网关
|
SQL 消息中间件 算法
Flink CDC 如何简化实时数据入湖入仓
本文整理自云邪、雪尽在 Flink Forward Asia 2021 的分享,该分享以 5 个章节详细介绍如何使用 Flink CDC 来简化实时数据的入湖入仓, 文章的主要内容如下: 1. Flink CDC 介绍 2. Flink CDC 的核心特性 3. Flink CDC 的开源生态 4. Flink CDC 在阿里巴巴的实践与改进 5. Flink CDC 的未来规划
10507 2
Flink CDC 如何简化实时数据入湖入仓
|
canal SQL 消息中间件
canal之高可用架构设计与应用
canal之高可用架构设计与应用