C语言表驱动法

最近了解到一种C语言的写法,故记录下来,内容来自deepseek。

表驱动法

表驱动法(Table-Driven Approach)是一种编程技术,通过使用表格(数组、结构体数组、哈希表等)来存储数据或逻辑,从而替代复杂的条件判断或重复代码。这种方法可以提高代码的可读性、可维护性和扩展性。

在C语言中,表驱动法通常通过数组或结构体数组来实现。以下是几个常见的应用场景和示例:

1. 替代复杂的条件判断

假设有一个函数根据输入的值返回对应的字符串,传统的写法可能是:

const char* getString(int value) {if (value == 1) {return "One";} else if (value == 2) {return "Two";} else if (value == 3) {return "Three";} else {return "Unknown";}
}

使用表驱动法可以简化为:

const char* getString(int value) {const char* strings[] = {"Unknown", "One", "Two", "Three"};if (value >= 1 && value <= 3) {return strings[value];}return strings[0];
}

2. 状态机

表驱动法常用于实现状态机。例如,假设有一个简单的状态机,根据当前状态和输入决定下一个状态:

typedef enum {STATE_A,STATE_B,STATE_C,NUM_STATES
} State;typedef enum {EVENT_X,EVENT_Y,NUM_EVENTS
} Event;State transitionTable[NUM_STATES][NUM_EVENTS] = {[STATE_A] = {STATE_B, STATE_C},[STATE_B] = {STATE_C, STATE_A},[STATE_C] = {STATE_A, STATE_B}
};State nextState(State current, Event event) {return transitionTable[current][event];
}

3. 命令分发

表驱动法可以用于命令分发。例如,假设有一组命令,每个命令对应一个处理函数:

typedef void (*CommandHandler)();void commandA() {printf("Command A executed\n");
}void commandB() {printf("Command B executed\n");
}void commandC() {printf("Command C executed\n");
}CommandHandler commandTable[] = {commandA, commandB, commandC};void executeCommand(int command) {if (command >= 0 && command < sizeof(commandTable) / sizeof(commandTable[0])) {commandTable[command]();} else {printf("Unknown command\n");}
}

4. 查找表

表驱动法还可以用于查找表,例如计算三角函数值:

double sinTable[] = {0.0, 0.5, 0.707, 0.866, 1.0};double getSinValue(int angle) {if (angle >= 0 && angle < sizeof(sinTable) / sizeof(sinTable[0])) {return sinTable[angle];}return 0.0;
}

优点

  • 可读性:表驱动法将逻辑和数据分离,代码更简洁易读。

  • 可维护性:修改逻辑时只需修改表格,而不需要修改代码。

  • 扩展性:添加新的条件或状态时,只需扩展表格,而不需要增加复杂的条件判断。

注意事项

  • 表格大小:表格的大小应合理,避免占用过多内存。

  • 边界检查:访问表格时需要进行边界检查,避免越界访问。

表驱动法是一种非常实用的编程技巧,适用于多种场景,能够有效简化代码并提高效率。

单片机开发

在单片机开发中,表驱动法与其他方法(如条件判断、函数调用、动态计算等)的对比需要从 内存占用(RAM/ROM)运行时间(CPU周期) 两个维度分析。以下是具体对比:

1. 内存占用对比

(1) 表驱动法
  • ROM/Flash 占用
    表驱动法需要预先存储静态表格(如数组、结构体数组),表格内容占用 ROM/Flash 空间。表格越大,ROM 占用越高。
    示例

const uint8_t LED_CODE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66}; // 0~4的数码管编码
  • 若表格有 100 个条目,每个条目占 1 字节,则 ROM 占用 100 字节。

  • RAM 占用
    若表格定义为 const(只读),通常存储在 ROM 中,不占用 RAM。若表格需要运行时修改(如动态配置表),则占用 RAM。

(2) 条件判断(if-else/switch-case)
  • ROM/Flash 占用
    条件判断的代码逻辑(如多个 if-elseswitch-case 分支)会编译为指令代码,占用 ROM。分支越多,指令代码越长。
    示例

uint8_t getLedCode(uint8_t num) {switch(num) {case 0: return 0x3F;case 1: return 0x06;case 2: return 0x5B;// ...}
}
  • 每个 case 分支对应一条或几条指令,ROM 占用随分支数量线性增长。

  • RAM 占用
    条件判断的代码逻辑不占用额外 RAM,仅需栈空间保存临时变量。

(3) 动态计算
  • ROM/Flash 占用
    动态计算(如实时计算三角函数)需要实现算法代码,可能占用较多 ROM(尤其是复杂算法)。
    示例

float sin(float x) { // 泰勒展开或其他算法实现
}

2. 运行时间对比

(1) 表驱动法
  • 时间复杂度
    查表操作的时间复杂度为 O(1)(直接索引),速度极快。
    示例

uint8_t code = LED_CODE[num]; // 直接访问内存地址

适合对实时性要求高的场景(如中断服务程序)。

(2) 条件判断(if-else/switch-case)
  • 时间复杂度
    时间复杂度为 O(n)(需要依次检查条件),分支越多,执行时间越长。
    示例
    若用 if-else 判断 100 个条件,最坏情况下需要比较 100 次。

  • 优化
    编译器可能对 switch-case 进行优化(如跳转表或二分查找),但效果不如手动设计的表驱动法。

(3) 动态计算
  • 时间复杂度
    取决于算法复杂度。
    示例

    • 泰勒展开计算 sin(x) 可能需要几十条指令。

    • 查表法只需一次内存访问,速度优势明显。

3. 对比总结

方法ROM 占用RAM 占用运行时间适用场景
表驱动法高(存储静态表)低(若用 const极快(O(1))数据映射、状态机、编码转换等
条件判断中(代码逻辑)慢(O(n))分支较少的逻辑(如 3~5 个分支)
动态计算高(算法代码)慢(依赖算法)无存储资源或需要高精度计算的场景

4. 单片机中的优化建议

  1. 表驱动法的适用场景

    • 数据映射(如 LED 编码、字符显示)。

    • 状态机(通过表格定义状态转移)。

    • 频繁调用的函数(如协议解析)。

  2. 条件判断的适用场景

    • 分支较少(如 3~5 个分支)。

    • 逻辑复杂且难以用表格表示。

  3. 动态计算的适用场景

    • 需要高精度计算(如浮点运算)。

    • 存储资源极度受限(无法存储大表格)。

  4. 混合策略

    • 对大表格进行压缩(如差值表、分段查表)。

    • 对高频访问的数据使用表驱动,低频逻辑用条件判断。


5. 示例对比

场景:根据输入值返回字符串
  • 表驱动法

const char* strings[] = {"A", "B", "C"};
return strings[input];
  • ROM 占用:3 条目 × 字符串长度。

  • 运行时间:1 次内存访问。

条件判断

if (input == 0) return "A";
else if (input == 1) return "B";
else return "C";
  • ROM 占用:3 条条件判断指令。

  • 运行时间:最多 3 次比较。

结论

  • 表驱动法 在运行时间上有显著优势,适合高频、实时性要求高的场景,但需要权衡 ROM 占用。

  • 条件判断 在分支较少时更灵活,代码更易维护。

  • 在资源受限的单片机中,需根据具体需求(实时性、存储限制)选择合适方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/17926.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3. 导入官方dashboard

官方dashboard&#xff1a;https://grafana.com/grafana/dashboards 1. 点击仪表板 - 新建 - 导入 注&#xff1a;有网络的情况想可以使用ID&#xff0c;无网络情况下使用仪表板josn文件 2. 在官方dashboard网页上选择符合你现在数据源的dashboard - 点击进入 3. 下拉网页选…

你如何利用SIMD(如SSE/AVX)优化图像处理的性能?

SIMD优化问题 1. SIMD 在图像处理中的优化方式2. 典型应用场景3. SIMD 的常见优化技巧4. 总结 利用 SIMD&#xff08;Single Instruction, Multiple Data&#xff09; 指令集&#xff08;如 SSE/AVX/AVX2/AVX-512&#xff09;优化图像处理的性能&#xff0c;可以极大地提升计算…

高并发场景下,如何用无锁实现高性能LRU缓存?

《百万人高并发场景下&#xff0c;我如何用无锁实现高性能LRU缓存&#xff1f;》 LRU算法核心原理 LRU&#xff08;Least Recently Used&#xff09;算法是缓存系统的核心淘汰策略&#xff0c;其核心逻辑可以用一张流程图描述&#xff1a; &#xff08;图&#xff1a;访问数…

HAL库框架学习总结

概述&#xff1a;HAL库为各种外设基本都配了三套 API&#xff0c;查询&#xff0c;中断和 DMA。 一、HAL库为外设初始化提供了一套框架&#xff0c;这里以串口为例进行说明&#xff0c;调用函数 HAL_UART_Init初始化串口&#xff0c;此函数就会调用 HAL_UART_MspInit&#xff0…

LAWS是典型的人机环境系统

致命性自主武器系统&#xff08;Lethal Autonomous Weapons Systems&#xff0c;LAWS&#xff09;是一种典型的人机环境系统&#xff0c;它通过高度集成的传感器、算法和武器平台&#xff0c;在复杂的战场环境中自主执行任务。LAWS能够自主感知环境、识别目标、做出决策并实施攻…

【16届蓝桥杯寒假刷题营】第1期DAY4

4.可达岛屿的个数 - 蓝桥云课 题目背景 在一个神奇的魔法世界中&#xff0c;有一座古老的迷幻之城。迷幻之城被分成 n 个鸟屿&#xff0c;编号从 1 到 n&#xff0c;共有 m 座桥。迷幻之城的居民们希望能够建立起紧密的联系&#xff0c;每个岛屿上的居民都想知道自己最多能到…

【物联网】电子电路基础知识

文章目录 一、基本元器件1. 电阻2. 电容3. 电感4. 二极管(1)符号(2)特性(3)实例分析5. 三极管(1)符号(2)开关特性(3)实例6. MOS管(产效应管)(1)符号(2)MOS管极性判定(3)MOS管作为开关(4)MOS管vs三极管7. 门电路(1)与门(2)或门(3)非门二、常用元器件…

数据结构 04

4. 栈 4.2. 链式栈 4.2.1. 特性 逻辑结构&#xff1a;线性结构 存储结构&#xff1a;链式存储结构 操作&#xff1a;创建&#xff0c;入栈&#xff0c;出栈&#xff0c;清空&#xff0c;获取 4.2.2. 代码实现 头文件 LinkStack.h #ifndef __LINKSTACK_H__ #define __LINKST…

【云安全】云原生-K8S(四)安全问题分析

Kubernetes&#xff08;K8S&#xff09;因其强大的容器编排能力成为了云计算和微服务架构的首选&#xff0c;但同时也带来了复杂的安全挑战。本文将概述K8S的主要安全问题&#xff0c;帮助安全工程师理解潜在威胁&#xff0c;并采取相应的防护措施。 K8S 攻击面概览 下面两张…

【Unity新手】Text不显示字的问题解决办法

很多同学在unity里导入了一个Text发现字没有显示出来为什么呢&#xff1f; 首先在网络上下载一个.ttf或者.otf字体文件&#xff0c;导入资源&#xff0c;比如说我下载了黑体.otf 然后导入unity&#xff0c;右键字体TextMesgPro-FontAsset 然后字体设置里添加上就可以了

基于Flask的影视剧热度数据可视化分析系统的设计与实现

【FLask】基于Flask的影视剧热度数据可视化分析系统的设计与实现&#xff08;完整系统源码开发笔记详细部署教程&#xff09;✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 随着互联网技术的飞速发展&#xff0c;影视剧行业的数据量呈爆炸性增长&#x…

React 低代码项目:组件设计

React 低代码项目&#xff1a;组件设计 Date: February 6, 2025 React表单组件 **目标&#xff1a;**使用 Ant Design 表单组件&#xff0c;开发登录、注册、搜索功能 内容&#xff1a; 使用 React 表单组件、受控组件使用 Ant Design 表单组件使用 表单组件的校验和错误提…

vue-plugin-hiprint (vue2

页面效果 <template><div><div class="d-flex flex-column mt5"><div class="d-flex flex-row " style="margin-bottom: 10px;justify-content: center;"><!-- 纸张大小 A3、A4 等 --><div class="paper…

C++17 中的 std::reduce:详细教程

文章目录 1. 简介2. 函数签名3. 使用场景3.1 简单的累加操作3.2 自定义归并操作3.3 并行计算的性能优势 4. 注意事项4.1 归并操作的结合律和交换律4.2 默认值的使用 5. 总结 1. 简介 std::reduce 是 C17 标准库中引入的一个算法&#xff0c;用于对范围内的元素进行归并操作。它…

kafka介绍,kafka集群环境搭建,kafka命令测试,C++实现kafka客户端

目录 kafka介绍kafka集群环境搭建zookeeper安装与配置kafka安装与配置 kafka命令测试C实现kafka客户端librdkafka库编译新版本cmake编译cppkafka库编译C实现kafka生产者和消费者客户端 kafka介绍 定义与概述 Apache Kafka 是一个开源的分布式流处理平台&#xff0c;最初由 Lin…

华为云+硅基流动使用Chatbox接入DeepSeek-R1满血版671B

华为云硅基流动使用Chatbox接入DeepSeek-R1满血版671B 硅基流动 1.1 注册登录 1.2 实名认证 1.3 创建API密钥 1.4 客户端工具 OllamaChatboxCherry StudioAnythingLLM 资源包下载&#xff1a; AI聊天本地客户端 接入Chatbox客户端 点击设置 选择SiliconFloW API 粘贴1.3创…

阿里云百炼平台对接DeepSeek官方文档

目录 1、支持的模型 2、快速开始 2.1、OpenAI兼容 2.1.1、python示例代码 返回结果 2.1.2、Node.js示例代码 返回结果 2.1.3、HTTP示例代码 返回结果 2.2、DashScope 2.2.1、python示例代码 返回结果 2.2.2、java示例代码 返回结果 2.2.3、HTTP代码示例 返回结…

【深度强化学习】策略梯度算法:REINFORCE

策略梯度 强化学习算法进阶 Q-learning、DQN 及 DQN 改进算法都是基于价值&#xff08;value-based&#xff09;的方法&#xff0c;其中 Q-learning 是处理有限状态的算法&#xff0c;而 DQN 可以用来解决连续状态的问题。在强化学习中&#xff0c;除了基于值函数的方法&#…

DeepSeek接口联调(postman版)

第一步&#xff1a;获取API key 获取APIkeys链接https://platform.deepseek.com/api_keys 点击创建 API key 即可免费生成一个key值&#xff0c;别忘记保存。 第二步&#xff1a;找到deepseek官方接口文档 文档地址&#xff1a;https://api-docs.deepseek.com/zh-cn/ 第三步…

Sublime Text 3 中的 Pylinter 配置

在 Sublime Text 3 中配置 Pylinter&#xff08;如 pylint&#xff09;来进行 Python 代码静态分析&#xff0c;可以帮助你提升代码质量、检测潜在的错误、强制遵守编码标准等。为了在 Sublime Text 3 中配置 pylint&#xff0c;你需要确保 pylint 已安装&#xff0c;并设置好相…