嵌入式C编程:宏定义与typedef的深入对比与应用
目录
一、宏定义(Macro Definition)
1.1. 特点与应用
1.1.1 定义常量
1.1.2 定义函数式宏
1.1.3 条件编译
1.2. 作用范围和生命周期方面
1.3. 应用注意事项
二、typedef
2.1. 特点与应用
2.1.1 简化类型声明
2.1.2 提高代码可读性
2.1.3 实现跨平台兼容性
2.2 作用范围和生命周期
2.2.1 作用范围
2.2.2 生命周期
三、对比总结
3.1. 工作原理
3.2. 类型安全性
3.3. 可读性
3.4. 应用场景
四、结论
在嵌入式C语言编程中,宏定义(Macro Definition)和typedef
是两个基础且功能强大的工具,它们在代码优化、可读性提升以及类型管理方面发挥着重要作用。尽管它们有时看起来相似,但实际上它们的工作原理和应用场景有着显著的区别。
一、宏定义(Macro Definition)
宏定义是通过预处理器指令#define
实现的,在编译代码之前,预处理器会对源代码中的宏定义进行文本替换。这个替换过程不涉及类型检查或语法分析,只是简单的文本替换。
1.1. 特点与应用
1.1.1 定义常量
宏定义最常见的应用之一是定义常量。这些常量在编译时就已经确定,并且在整个程序中都保持不变。使用宏定义定义的常量可以提高代码的可读性和可维护性。
示例:
#define PI 3.14159
在这个例子中,PI
被定义为一个常量,其值为3.14159。在程序中的任何地方,每当预处理器遇到PI
时,它都会将其替换为3.14159。
1.1.2 定义函数式宏
除了定义常量外,宏定义还可以用于定义函数式宏。函数式宏是一种特殊的宏,它看起来像函数调用,但实际上在预处理阶段就被替换为一段代码。这种宏可以用于简化代码,但需要注意的是,由于它们不涉及类型检查,因此使用时需要格外小心以避免类型不匹配导致的错误。
示例:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
在这个例子中,MAX
是一个函数式宏,用于计算两个数中的较大值。当预处理器遇到MAX(x, y)
时,它会将其替换为((x) > (y) ? (x) : (y))
。
1.1.3 条件编译
宏定义还可以与条件编译指令结合使用,以实现代码的条件编译。条件编译允许开发者根据特定的条件(如是否定义了某个宏)来选择性地编译代码的一部分。这对于调试、测试不同版本的代码或在不同平台上编译代码非常有用。
示例:
#ifdef DEBUG// 调试代码
#else// 发布代码
#endif
在这个例子中,如果定义了DEBUG
宏,则预处理器会编译#ifdef
和#else
之间的代码;否则,它会编译#else
和#endif
之间的代码。
1.2. 作用范围和生命周期方面
宏定义的作用域从定义处开始,到文件末尾结束(除非被#undef
取消定义)。它在预处理阶段就完成了替换,不存在像变量一样的生命周期概念。例如:
#define MAX(a,b) ((a) > (b)? (a) : (b))
int main()
{int result = MAX(3, 5);return 0;
}
在预处理阶段,MAX(3, 5)
就被替换为((3)>(5)?(3):(5))
,这个替换是全局的,只要在定义之后的代码中出现MAX
宏,都会进行这样的替换。
1.3. 应用注意事项
- 类型安全性:由于宏定义只是简单的文本替换,因此不具有类型安全性。如果宏被错误地使用或替换,可能会导致编译错误或运行时错误。因此,在使用宏定义时需要格外小心,确保类型匹配。
- 可读性和可维护性:虽然宏定义可以简化代码,但过度使用或不当使用会降低代码的可读性和可维护性。因此,在使用宏定义时需要权衡其带来的好处和潜在的负面影响。
- 命名规范:为了避免命名冲突和提高代码的可读性,建议使用大写字母来命名宏定义(如
PI
、MAX
等)。
宏定义是嵌入式C编程中一个非常有用的工具,它允许开发者在编译之前对源代码进行文本替换。正确地使用宏定义可以简化代码、提高代码的可读性和可维护性,但需要注意其类型安全性和潜在的风险。
二、typedef
typedef是C语言中的一个关键字,它允许开发者为已存在的类型创建新的名称(别名)。这种机制在增强代码可读性、简化复杂类型声明以及实现跨平台兼容性方面发挥着重要作用。
2.1. 特点与应用
2.1.1 简化类型声明
typedef可以显著简化复杂类型的声明。例如,对于结构体、联合体或指针等类型,使用typedef可以为其创建一个更易读、更简洁的别名。
示例1:简化结构体类型声明
#include <stdio.h>// 使用typedef为结构体类型创建别名
typedef struct {int x;int y;
} Point;int main() {Point p1; // 使用Point别名声明结构体变量p1.x = 10;p1.y = 20;printf("Point p1: (%d, %d)\n", p1.x, p1.y);return 0;
}
在这个例子中,typedef
为包含x
和y
两个整数的结构体创建了一个名为Point
的别名。这使得在声明结构体变量时,可以直接使用Point
而不是完整的struct { int x; int y; }
。
示例2:为指针类型创建别名
#include <stdio.h>// 使用typedef为指针类型创建别名
typedef int* IntPtr;int main() {int value = 42;IntPtr ptr = &value; // 使用IntPtr别名声明指针变量printf("Value: %d, Pointer: %p\n", value, (void*)ptr);return 0;
}
在这个例子中,typedef
为指向int
类型的指针创建了一个名为IntPtr
的别名。这使得在声明指向整数的指针时,可以直接使用IntPtr
而不是int*
。
示例3:在函数参数中使用typedef
#include <stdio.h>// 使用typedef为结构体类型创建别名
typedef struct {int length;int width;
} Rectangle;// 函数声明,使用Rectangle作为参数类型
void printRectangleArea(Rectangle rect) {int area = rect.length * rect.width;printf("Rectangle Area: %d\n", area);
}int main() {Rectangle rect = {5, 10}; // 使用Rectangle别名声明结构体变量printRectangleArea(rect); // 调用函数,传递Rectangle类型的参数return 0;
}
2.1.2 提高代码可读性
通过为复杂类型创建别名,typedef可以提高代码的可读性。这尤其适用于那些包含多个成员的结构体或联合体类型,以及那些涉及多层指针的类型。使用typedef可以为这些类型创建一个更具描述性的名称,从而使代码更加易于理解。
2.1.3 实现跨平台兼容性
在嵌入式系统开发中,不同平台之间的数据类型大小可能有所不同。使用typedef可以为这些平台特定的类型创建统一的别名,从而实现跨平台的代码兼容性。例如,可以使用typedef为整数类型创建一个平台无关的别名,以确保在不同平台上编译和运行时的一致性。
2.2 作用范围和生命周期
2.2.1 作用范围
typedef定义的类型别名的作用范围与普通类型相同。它们可以在块级作用域(如函数内部)或文件作用域(如全局范围内)内定义。在块级作用域内定义的别名只能在该作用域内使用,而在文件作用域内定义的别名则可以在整个文件中使用。
示例:
#include <stdio.h>void func() {typedef char CharAlias; // 在块级作用域内定义别名CharAlias c = 'A'; // 使用CharAlias别名声明变量printf("Character: %c\n", c);
}int main() {// 在这里不能使用CharAlias,因为它的作用域在func函数内部func();return 0;
}
在这个例子中,typedef
在func
函数的块级作用域内为char
类型创建了一个名为CharAlias
的别名。这个别名只能在func
函数内部使用。在main
函数中尝试使用CharAlias
会导致编译错误。
2.2.2 生命周期
typedef定义的类型别名的生命周期与程序的运行周期相同。只要在其作用域内,就可以使用该别名来声明变量。这意味着,一旦在程序中定义了某个类型的别名,就可以在该程序的生命周期内随时使用该别名来创建该类型的变量。
typedef是C语言中一个非常有用的工具,它允许开发者为已存在的类型创建新的名称(别名)。通过简化类型声明、提高代码可读性和实现跨平台兼容性等方面的应用,typedef可以显著提高代码的质量和可维护性。同时,了解typedef的作用范围和生命周期也是正确使用它的关键。
三、对比总结
3.1. 工作原理
-
宏定义:宏定义在预处理阶段进行文本替换。预处理器在编译之前扫描源代码,将宏名称替换为其定义的文本内容。这个过程不涉及类型检查,仅仅是文本层面的替换。
-
typedef:typedef在编译阶段为已存在的类型创建新的名称(别名)。编译器会识别typedef定义,并在后续的编译过程中使用这些别名。typedef会进行类型检查,确保别名与原始类型的一致性。
3.2. 类型安全性
-
宏定义:由于宏定义只是简单的文本替换,不提供类型安全性。如果宏定义用于表示某种类型,但在使用时发生了类型不匹配,编译器可能不会立即报错(直到后续操作导致错误时),这增加了调试的难度。
-
typedef:typedef提供了类型安全性。由于它是在编译阶段处理的,编译器能够检查别名与原始类型的一致性。如果别名被错误地使用(例如,尝试将别名应用于不兼容的类型),编译器将报错,这有助于在编译阶段发现并修复错误。
3.3. 可读性
-
宏定义:虽然宏定义可以简化代码(例如,通过定义常量或函数式宏来减少重复代码),但过度使用或不当使用会降低代码的可读性。特别是当宏定义涉及复杂的表达式或逻辑时,阅读和理解代码变得更加困难。
-
typedef:typedef通常用于提高代码的可读性和可维护性。通过为复杂的数据类型(如结构体、联合体、指针等)创建别名,typedef使代码更加清晰易懂。这有助于开发者更快地理解代码的结构和逻辑。
3.4. 应用场景
- 宏定义:
- 定义常量:使用#define定义常量值,以便在代码中多次使用而无需重复书写。
- 函数式宏:通过宏定义实现类似函数的代码片段,但需要注意的是,函数式宏通常不如真正的函数安全(因为它们不进行类型检查,并且可能导致意外的副作用)。
- 条件编译:使用#ifdef、#ifndef、#if等预处理指令根据条件编译不同的代码段。
- typedef:
- 为复杂数据类型创建别名:例如,为结构体、联合体、指针等类型创建更易读、更简洁的别名。
- 提高代码可读性:通过typedef,可以使代码更加清晰易懂,特别是当处理复杂的数据结构时。
- 实现跨平台兼容性:使用typedef可以为不同平台上的类型创建统一的别名,从而实现跨平台的代码兼容性。
宏定义和typedef在C语言中都有各自的应用场景和优缺点。开发者应根据具体需求和使用场景选择合适的工具来优化代码。在使用宏定义时,应谨慎避免过度使用或不当使用,以免降低代码的可读性和可维护性。在使用typedef时,应充分利用其提高代码可读性和类型安全性的优势。
四、结论
在嵌入式C编程中,宏定义和typedef
是两种极为有用的工具,它们各自具有独特的优势和应用场景。
宏定义通过预处理阶段的文本替换功能,为开发者提供了强大的代码复用和条件编译能力。这使得开发者能够轻松地定义常量、创建函数式宏,以及根据编译条件包含或排除特定的代码段。然而,宏定义也存在一些潜在的缺点,如类型不安全性和可能降低代码可读性。因此,在使用宏定义时,开发者需要谨慎考虑其潜在影响,并尽量避免过度使用或不当使用。
另一方面,typedef
则为C语言中的类型系统提供了灵活性和可读性方面的增强。通过为复杂的数据类型创建简洁明了的别名,typedef
使得代码更加易于理解和维护。此外,typedef
还提供了类型安全性,有助于减少因类型不匹配而导致的编译错误或运行时错误。这使得typedef
在嵌入式C编程中得到了广泛的应用,特别是在处理结构体、联合体、指针等复杂数据类型时。
综上所述,宏定义和typedef
在嵌入式C编程中各自扮演着重要的角色。正确地使用这两个工具可以显著提高代码的质量、可读性和性能。开发者应根据具体需求和使用场景选择合适的工具来优化代码,并始终注意保持代码的清晰、简洁和易于维护。通过合理利用宏定义和typedef
,开发者可以编写出更加高效、可靠和易于理解的嵌入式C程序。
相关文章:
嵌入式C编程:宏定义与typedef的深入对比与应用
目录 一、宏定义(Macro Definition) 1.1. 特点与应用 1.1.1 定义常量 1.1.2 定义函数式宏 1.1.3 条件编译 1.2. 作用范围和生命周期方面 1.3. 应用注意事项 二、typedef 2.1. 特点与应用 2.1.1 简化类型声明 2.1.2 提高代码可读性 2.1.3 实现…...
算法复杂度
目录: 算法的效率时间复杂度 1.算法的效率 1.1旋转数组习题分析 如何衡量一个算法的好坏呢? 案例:旋转数组(189. 轮转数组 - 力扣(LeetCode)) 思路:循环k次将所有元素向后移动一…...
时序约束进阶六:Set_Clock_Groups详解
目录 一、前言 二、时钟间关系 2.1 时钟关系分类 2.2 时钟关系查看 三、set_clock_groups设置 3.1 使用格式 3.2 优先级 3.3 约束设置示例 3.4 约束效果查看 四、Exclusive差异说明 4.1 Asynchronous 4.2 Logically_exclusive与Physically_exclusive 4.3 logical…...
《运放秘籍》第二部:仪表放大器专项知识点总结
一、差分放大器与仪表放大器的讨论 1.1. 仪放的前世今生——差分放大器原理? 1.2. 差分放大的原理 1.3. 差分放大器检测电流 1.4. 差分放大器端一:输入阻抗 1.5. 差分放大器端二:共模抑制比 1.6. 为什么关注输入阻抗?共模抑…...
JavaSE——异常
一、异常的概念 在Java中,将程序执行中发生的不正常行为称为"异常",开发过程中的语法错误和逻辑错误不是异常。 主要分为以下两大类: Error(错误):Java虚拟机无法解决的严重问题,是严重错误,程序…...
HormonyOS: 图形变换之Rotate
官网地址:rotate 1. 概述 rotate是鸿蒙系统为组件提供的旋转属性,通过rotate属性,可实现组件的旋转效果 2. rotate属性 2.1. 语法参数 rotate(value: RotateOptions) 参数: 参数名 类型 必填 说明 value RotateOptions…...
【Solidity】入门指南:智能合约开发基础
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 Solidity入门指南:智能合约开发基础引言1. 开发环境搭建1.1 Remix I…...
HTMLHTML5革命:构建现代网页的终极指南 - 3. 开发工具选择
HTML&HTML5革命:构建现代网页的终极指南 3. 开发工具选择 大家好,我是莫离老师。 前两节课我们学习了 HTML 的基础概念和 HTML5 的主要特性,为接下来的实际开发奠定了理论基础。 今天,我们将讨论开发工具的选择问题。 选择合…...
智能设备安全隐患:五项关键解决措施
目前,我们的智能设备越来越多,而背后的物联网(IoT)安全像一面隐形的盾牌,默默地守护着我们周围那些复杂连网的设备。 为了让大家更加明白这些安全协议和操作是如何高效运作的,我们有必要深入探讨物联网安全…...
Android NDK开发 JNI 基础
在android 系统开发中 ndk开发是很重要的内容。ndk开发中 jni 是基础。 目录 一.什么是JNI 二. 如何使用JNI 1.Java 代码如何调用 c/c 代码 2. c/c如何调用 java 函数 一.什么是JNI JNI——Java Native Interface,它是Java平台的一个特…...
嵌入式linux之文件系统管理
嵌入式Linux文件系统的管理涉及多个方面,包括文件系统的创建、配置、维护以及优化。以下是一些关键点和实践技巧: 文件系统的创建与配置 选择合适的文件系统:根据应用需求(如读写频率、存储介质类型等)选择最合适的文…...
Y20030029 微信+SPRINGBOOT+MYSQL+LW+传统文化展示小程序的设计与实现 源代码 配置 文档
传统文化展示小程序 1.项目描述2. 课题开发的背景与意义3.项目功能4.界面展示5.源码获取 1.项目描述 基于微信小程序的传统文化展示小程序是一个集合了多种传统文化元素与现代化技术的创新平台。它充分利用了微信小程序的便捷性和普及性,为广大用户提供了一个深入了…...
【LC】3232. 判断是否可以赢得数字游戏
题目描述: 给你一个 正整数 数组 nums。 Alice 和 Bob 正在玩游戏。在游戏中,Alice 可以从 nums 中选择所有个位数 或 所有两位数,剩余的数字归 Bob 所有。如果 Alice 所选数字之和 严格大于 Bob 的数字之和,则 Alice 获胜。如果…...
【人工智能基础03】机器学习(练习题)
文章目录 课本习题监督学习的例子过拟合和欠拟合常见损失函数,判断一个损失函数的好坏无监督分类:kmeans无监督分类,Kmeans 三分类问题变换距离函数选择不同的起始点 重点回顾1. 监督学习、半监督学习和无监督学习的定义2. 判断学习场景3. 监…...
C/C++每日一练:合并K个有序链表
本篇博客将探讨如何 “合并K个有序链表” 这一经典问题。本文将从题目要求、解题思路、过程解析和相关知识点逐步展开,同时提供详细注释的代码示例。 链表(Linked List) 链表是一种线性数据结构,由一系列节点(Node&…...
jmeter基础07_组件的层级
课程大纲 1. 优先级/执行顺序(一般情况) 同级组件:按组件先后顺序执行。如:同一层的线程组、同一层的http请求。 上下级组件:先执行外层(上级),再执行内层(下级ÿ…...
【QNX+Android虚拟化方案】125 - 如何创建android-spare镜像
【QNX+Android虚拟化方案】125 - 如何创建android-spare镜像 1. Android侧创建 (ext4 / sparse) test_img.img 镜像 方法一2. Android侧创建 (ext4 / sparse) test_img.img 镜像 方法二3. qnx 侧 分区透传Android 配置3.1 配置分区透传3.2 Android 侧分区 rename3.3 创建挂载目…...
大R玩家流失预测在休闲社交游戏中的应用
摘要 预测玩家何时会离开游戏为延长玩家生命周期和增加收入贡献创造了独特的机会。玩家可以被激励留下来,战略性地与公司组合中的其他游戏交叉链接,或者作为最后的手段,通过游戏内广告传递给其他公司。本文重点预测休闲社交游戏中高价值玩家…...
使用Postman搞定各种接口token实战
现在许多项目都使用jwt来实现用户登录和数据权限,校验过用户的用户名和密码后,会向用户响应一段经过加密的token,在这段token中可能储存了数据权限等,在后期的访问中,需要携带这段token,后台解析这段token才…...
【C++】printf 函数详解与格式化输出控制
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯printf 基础用法1.1 printf 的常见占位符1.2 占位符与参数的对应关系1.3 换行控制示例: 💯格式化输出控制2.1 输出宽度控制2.1.1 指定最小宽度 2.2 …...
在21世纪的我用C语言探寻世界本质——字符函数和字符串函数(1)
人无完人,持之以恒,方能见真我!!! 共同进步!! 文章目录 一、字符分类函数二、字符转换函数三、strlen的使用和模拟实现四、strcpy的使用和模拟实现五、strcat的使用和模拟实现六、strcmp的使用和…...
【专题】存储器管理
1. 存储器的层次结构 在计算机执行时,几乎每一条指令都涉及对存储器的访问,因此要求对存储器的访问速度能跟得上处理机的运行速度。 存储器的速度必须非常快,能与处理机的速度相匹配,否则会明显地影响到处理机的运行。 此外还要求…...
python股票数据分析(Pandas)练习
需求: 使用pandas读取一个CSV文件,文件内容包括股票名称、价格和交易量。完成以下任务: 找出价格最高的股票; 计算总交易量; 绘制价格折线图。 代码实现: import pandas as pd import matplotlib.pyplot …...
Hadoop生态圈框架部署(八)- Hadoop高可用(HA)集群部署
文章目录 前言一、部署规划二、Hadoop HA集群部署(手动部署)1. 下载hadoop2. 上传安装包2. 解压hadoop安装包3. 配置hadoop配置文件3.1 虚拟机hadoop1修改hadoop配置文件3.1.1 修改 hadoop-env.sh 配置文件3.3.2 修改 core-site.xml 配置文件3.3.3 修改 …...
抗干扰设计的检查细则
抗干扰设计是确保电子系统或设备在复杂电磁环境中稳定运行的重要环节,涉及多个方面的设计和实施。以下是对抗干扰设计的检查细则的详细归纳: 一、电源线与地线设计 电源线设计:选择合适的电源,尽量加宽电源线,保证电源…...
[Redis#12] 常用类型接口学习 | string | list
目录 0.准备 1.string get | set set_with_timeout_test.cpp set_nx_xx_test.cpp mset_test.cpp mget_test.cpp getrange_setrange_test.cpp incr_decr_test.cpp 2.list lpush_lrange_test.cpp rpush_test.cpp lpop_rpop_test.cpp blpop_test.cpp llen_test.cpp…...
React的ts文件中通过createElement拼接一段内容出来
比如接口返回一个值 const values [23.00, 40.00/kg];想做到如下效果, 如果单纯的用render渲染会很简单, 但是在ts文件中处理,所以采用了createElement拼接 代码如下: format: (values: string[]) > {if (!values || !val…...
【Git系列】Git 提交历史分析:深入理解`git log`命令
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
深度学习笔记——生成对抗网络GAN
本文详细介绍早期生成式AI的代表性模型:生成对抗网络GAN。 文章目录 一、基本结构生成器判别器 二、损失函数判别器生成器交替优化目标函数 三、GAN 的训练过程训练流程概述训练流程步骤1. 初始化参数和超参数2. 定义损失函数3. 训练过程的迭代判别器训练步骤生成器…...
《地球科学与环境学报》
《地球科学与环境学报》报道范围涵盖基础地质、矿产地质、水资源与环境、工程地质、地球物理、地球信息科学等领域,刊载国内外未公开发表的有创新性或意义重大的研究论文和综述文章。 来稿必须包括以下项目:题名(尽可能不要超过20字&…...
k8s 1.28 聚合层部署信息记录
–requestheader-client-ca-file –requestheader-allowed-namesfront-proxy-client –requestheader-extra-headers-prefixX-Remote-Extra- –requestheader-group-headersX-Remote-Group –requestheader-username-headersX-Remote-User –proxy-client-cert-file –proxy-cl…...
组件化设计的意义
鸿蒙操作系统(HarmonyOS)是华为公司开发的一款面向未来、面向全场景的分布式操作系统。它不仅能够支持多种智能终端设备,还能够实现跨设备之间的协同工作。为了满足不同设备的资源能力和业务需求,鸿蒙操作系统采用了组件化的设计方…...
2025 年河北省职业院校大数据应用与 服务(中职组)赛项样题
— 1 — 2025 年河北省职业院校大数据应用与 服务(中职组)赛项样题 一、背景描述 近年来,随着旅游业的快速发展和社交媒体的普及,一 些目的地因其独特的魅力或者事件而迅速走红,吸引了大量 游客涌入,使得当…...
宏集eXware物联网网关在水务管理系统上的应用
一、前言 水务管理系统涵盖了对城市水网、供水、排水、污水处理等多个环节的监控与管理。随着物联网(IoT)技术的快速发展,物联网网关逐渐成为水务管理系统中的关键组成部分。 宏集物联网网关以其高效的数据采集、传输和管理功能,…...
【看海的算法日记✨优选篇✨】第三回:二分之妙,寻径中道
🎬 个人主页:谁在夜里看海. 📖 个人专栏:《C系列》《Linux系列》《算法系列》 ⛰️ 一念既出,万山无阻 目录 📖一、算法思想 细节问题 📚左右临界 📚中点选择 📚…...
yolov5 解决:export GIT_PYTHON_REFRESH=quiet
当我们在第一次运行YOLOv5中的train.py程序时:可能会出现以下报错: This initial warning can be silenced or aggravated in the future by setting the $GIT_PYTHON_REFRESH environment variable. Use one of the following values: - quiet|q|silen…...
MongoDB聚合操作
1.聚合操作 聚合操作处理数据记录并返回计算结果。聚合操作组值来自多个文档,可以对分组数据执行各种操作以返回单个结果。聚合操作包含三类:单一作用聚合、聚合管道、MapReduce。 单一作用聚合:提供了对常见聚合过程的简单访问,…...
Apple雷电5到底有多快?
在科技日新月异的今天,苹果公司始终走在技术创新的前沿。2023年9月12日,随着英特尔发布雷电5(Thunderbolt 5)规范,苹果迅速跟进,将其应用于自家的产品中。雷电5接口以其卓越的性能,彻底颠覆了我…...
项目快过:知识蒸馏 | 目标检测 |FGD | Focal and Global Knowledge Distillation for Detectors
公开时间:2022年3月9号 项目地址:https://github.com/yzd-v/FGD 论文地址:https://arxiv.org/pdf/2111.11837 知识蒸馏已成功地应用于图像分类。然而,目标检测要复杂得多,大多数知识蒸馏方法都失败了。本文指出&#…...
Spring Boot日志总结
文章目录 1.我们的日志2.日志的作用3.使用日志对象打印日志4.日志框架介绍5.深入理解门面模式(外观模式)6.日志格式的说明7.日志级别7.1日志级别分类7.2配置文件添加日志级别 8.日志持久化9.日志文件的拆分9.1官方文档9.2IDEA演示文件分割 10.日志格式的配置11.更简单的日志输入…...
PostgreSQL最常用数据类型-重点说明自增主键处理
简介 PostgreSQL提供了非常丰富的数据类型,我们平常使用最多的基本就3类: 数字类型字符类型时间类型 这篇文章重点介绍这3中类型,因为对于高并发项目还是推荐:尽量使用简单类型,把运算和逻辑放在应用中,…...
androidstudio 最新继承 proto kts 方式
在Android Studio中,如果你使用的是Kotlin DSL(.kts文件)来配置你的Gradle项目,并且你想集成Protocol Buffers(Proto),你需要稍微调整你的配置方式。以下是如何在Kotlin DSL中配置Proto集成的步…...
【STM32学习】TB6612FNG驱动芯片的学习,驱动电路的学习
目录 1、TB6612电机驱动芯片 1.1如下是芯片的引脚图: 1.2如下图是电机的控制逻辑: 1.3MOS管运转逻辑 1.3典型应用电路 2、H桥驱动电路 2.1、单极模式 2.2、双极模式 2.3、高低端MOS管导通条件 2.4、H桥电路设计 2.5、自举电路 3、电气特性 3…...
【AI战略思考13】克服懒惰,保持专注,提升效率,不再焦虑
【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 引言 我发现自己最近非常懒惰,浪费了很多时间,也容易分心,不够专注,效率低下,且每天都有点焦虑,因此制定了下面的要求和作息时间表。 目…...
基于Vue3+Element Plus 实现多表单校验
使用场景 表单校验在日常的开发需求中是一种很常见的需求,通常在提交表单发起请求前校验用户输入是否符合规则,通常只需formRef.value.validate()即可校验,但是,例如一些多步骤表单、动态表单、以及不同的用户角色可能看到不同的表…...
“岗位复合化、技能层次化” 高职大数据技术专业人才培养实践
在全球数字化浪潮的推动下,大数据技术已经成为引领社会进步和经济发展的核心动力。随着《关于深化现代职业教育体系建设改革的意见》等系列指导问文件的发布,我国高职大数据技术专业的教育正迎来全新机遇与挑战。这些政策不仅明确了职业教育改革的方向&a…...
Day2 生信新手笔记: Linux基础
一、基础知识 1.1 服务器 super computer 或 server 1.2 组学数据分析 组学数据:如基因组学、转录组学、蛋白质组学等; 上游分析:主要涉及原始数据的获取和初步处理,计算量大,消耗的资源较多,在服务器完…...
AI开发-数据可视化库-Seaborn
1 需求 概述 Seaborn 是一个基于 Python 的数据可视化库,它建立在 Matplotlib 之上。其主要目的是使数据可视化更加美观、方便和高效。它提供了高层次的接口和各种美观的默认主题,能够帮助用户快速创建出具有吸引力的统计图表,用于数据分析和…...
如何把Qt exe文件发送给其他人使用
如何把Qt exe文件发送给其他人使用 1、先把 Debug改成Release2、重新构建项目3、运行项目4、找到release文件夹5、新建文件夹,存放exe文件6、打开qt控制台串口7、下载各种文件8、压缩,发送压缩包给别人 1、先把 Debug改成Release 2、重新构建项目 3、运行…...
力扣103.二叉树的锯齿形层序遍历
题目描述 题目链接103. 二叉树的锯齿形层序遍历 给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。 示例 1ÿ…...