README_条件编译笔记

news2026/5/7 15:32:46
条件编译笔记1. 这篇笔记讲什么这篇笔记不是泛泛而谈 C 语言预处理器而是结合你当前 STM32 工程里的真实代码来讲清楚什么是条件编译它和普通if判断有什么本质区别你的项目里哪些地方正在使用条件编译这些写法分别解决什么问题后面你自己改工程时哪些宏可以改哪些不要随便动工程路径D:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试2. 什么是条件编译条件编译属于C 预处理器preprocessor的工作。一个.c文件在真正编译成目标代码之前会先经过“预处理”阶段。这个阶段会先处理#include#define#undef#if#ifdef#ifndef#elif#else#endif所以条件编译的本质是在“编译之前”先决定某一段代码到底保不保留。也就是说编译器真正看到的代码已经是“预处理之后”的结果了。3. 条件编译和普通if的区别这是最容易混淆的点。3.1 运行时ifif(flag){func();}特点这段代码一定会参与编译程序运行时才判断flag会产生运行时分支开销3.2 编译时#if#ifLOG_LEVEL1UsartPrintf(...);#endif特点预处理阶段就决定保不保留条件不成立时这段代码会直接从源文件里“消失”不产生运行时判断开销一句话总结if运行时选路径#if编译前选代码这也是为什么单片机项目特别喜欢用条件编译节省 Flash 空间减少串口打印去掉不必要的模块控制不同芯片、不同板型、不同编译选项下的代码分支4. 你这个项目里条件编译主要分哪几类结合工程里的实际代码可以大致分为 5 类日志等级控制C / C 兼容包装HAL 模块开关与默认参数兜底芯片型号、硬件能力、启动方式相关分支头文件防重复包含这里我把“头文件防重复包含”故意放到后面讲因为它虽然最常见但如果一上来就讲它反而容易把条件编译的核心原理冲淡。我们先把“真的会改变功能路径”的几类理解透再回来看头文件保护会更顺。5. 日志等级控制这一部分我按你第一次给我那段代码时的讲法重新写得更“拆解式”一点。对应文件D:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\APP\bsp_usart.h原代码#ifndefLOG_LEVEL#defineLOG_LEVEL1#endif#ifLOG_LEVEL2#defineLOG_DEBUG(...)UsartPrintf(USART_DEBUG,__VA_ARGS__)#else#defineLOG_DEBUG(...)#endif#ifLOG_LEVEL1#defineLOG_INFO(...)UsartPrintf(USART_DEBUG,__VA_ARGS__)#else#defineLOG_INFO(...)#endif#defineLOG_WARN(...)UsartPrintf(USART_DEBUG,__VA_ARGS__)#defineLOG_ERROR(...)UsartPrintf(USART_DEBUG,__VA_ARGS__)这段代码的目的很简单用LOG_LEVEL控制日志输出等级在编译阶段决定哪些日志代码保留哪些日志代码直接删掉也就是说它不是“运行时判断要不要打印”而是“编译前就决定这行代码存不存在”。5.1#ifndef LOG_LEVEL是什么意思#ifndefLOG_LEVEL#defineLOG_LEVEL1#endif等价理解如果LOG_LEVEL没有被定义那就给它一个默认值1这里的作用是设置默认日志等级。比如如果你在别处没有写#define LOG_LEVEL 2那这里就自动使用1所以它是一种“默认配置兜底”。5.2#if LOG_LEVEL 2是什么意思#ifLOG_LEVEL2#defineLOG_DEBUG(...)UsartPrintf(USART_DEBUG,__VA_ARGS__)#else#defineLOG_DEBUG(...)#endif等价理解如果日志等级大于等于2那LOG_DEBUG(...)就真的展开成UsartPrintf(...)否则LOG_DEBUG(...)展开成空这里最关键的是“展开成空”。也就是LOG_DEBUG(value%d\r\n,x);当LOG_LEVEL 2时预处理后会直接变成;你也可以粗略理解成这句日志根本不存在了编译器后面看到的代码里已经没有这条调试打印5.3...和__VA_ARGS__是什么这是你这次最关心的点我们把它拆细一点。例如#defineLOG_INFO(...)UsartPrintf(USART_DEBUG,__VA_ARGS__)这里的...表示“参数数量不固定”__VA_ARGS__表示“把传进来的参数原样代入”这叫可变参数宏。也就是说LOG_INFO后面可以接任意数量的参数。例如LOG_INFO(hello\r\n);LOG_INFO(x%d\r\n,x);LOG_INFO(id%d name%s\r\n,id,name);这三种都合法。它们的展开结果分别类似于UsartPrintf(USART_DEBUG,hello\r\n);UsartPrintf(USART_DEBUG,x%d\r\n,x);UsartPrintf(USART_DEBUG,id%d name%s\r\n,id,name);所以你可以把它记成...负责把所有参数“收起来”__VA_ARGS__负责把收起来的参数“原样倒出去”这个理解非常重要。5.4 为什么日志宏这里必须用...因为日志打印本来就像printf有时候只打一段固定字符串有时候打一段格式串加一个变量有时候打一段格式串加多个变量如果不用可变参数宏你就得写很多版本#defineLOG_INFO0(str)...#defineLOG_INFO1(fmt,a)...#defineLOG_INFO2(fmt,a,b)...这样既丑也难维护。而用了#defineLOG_INFO(...)UsartPrintf(USART_DEBUG,__VA_ARGS__)你就能一直保持和printf一样的调用风格。5.5 这段代码在不同LOG_LEVEL下的效果当LOG_LEVEL 0LOG_DEBUG(...)被展开为空LOG_INFO(...)被展开为空LOG_WARN(...)仍然打印LOG_ERROR(...)仍然打印效果只保留警告和错误日志当LOG_LEVEL 1LOG_DEBUG(...)被展开为空LOG_INFO(...)会打印LOG_WARN(...)会打印LOG_ERROR(...)会打印效果打印普通信息、警告、错误不打印调试细节当LOG_LEVEL 2LOG_DEBUG(...)会打印LOG_INFO(...)会打印LOG_WARN(...)会打印LOG_ERROR(...)会打印效果所有日志都打印5.6 用预处理器展开后的直观结果原代码LOG_DEBUG(debug: %d\r\n,a);LOG_INFO(info: %d\r\n,b);LOG_WARN(warn: %d\r\n,c);当LOG_LEVEL 1预处理后大致变成;UsartPrintf(USART_DEBUG,info: %d\r\n,b);UsartPrintf(USART_DEBUG,warn: %d\r\n,c);当LOG_LEVEL 2预处理后大致变成UsartPrintf(USART_DEBUG,debug: %d\r\n,a);UsartPrintf(USART_DEBUG,info: %d\r\n,b);UsartPrintf(USART_DEBUG,warn: %d\r\n,c);所以它的本质就是编译前替换编译前裁剪代码5.7 这种写法的优点5.7.1 没有运行时开销如果写成if(log_level2){UsartPrintf(...);}那么即使不打印程序运行时也还要判断一次。而条件编译是不满足条件时直接不生成这部分代码所以运行时更省。5.7.2 适合单片机单片机项目通常很关心Flash 空间RAM 空间串口打印耗时实时性日志太多会影响速度条件编译正好适合做裁剪。5.7.3 管理方便只改一处#defineLOG_LEVEL2就能控制整个工程的日志详细程度。5.8LOG_WARN和LOG_ERROR为什么没做条件编译#defineLOG_WARN(...)UsartPrintf(USART_DEBUG,__VA_ARGS__)#defineLOG_ERROR(...)UsartPrintf(USART_DEBUG,__VA_ARGS__)说明作者当前的设计意图是WARN和ERROR永远保留不受LOG_LEVEL限制因为这两类信息通常更重要。如果你以后也想让它们受等级控制也可以改成#ifLOG_LEVEL1#defineLOG_WARN(...)UsartPrintf(USART_DEBUG,__VA_ARGS__)#else#defineLOG_WARN(...)#endif5.9 这种写法和函数有什么区别例如你可能会想voidLOG_INFO(constchar*fmt,...){...}宏和函数的区别宏预处理阶段替换可以被条件编译直接裁掉没有函数调用开销函数运行时调用即使想关闭日志函数本身通常还在更容易调试类型检查也更清晰所以在嵌入式里高频日志调试开关通常更喜欢用宏。5.10 这一节你最好记住的三句话你可以把日志等级控制先记成下面这三句#ifndef LOG_LEVEL如果没配置日志等级就给一个默认值。...表示这个宏可以接收不定数量参数。__VA_ARGS__把这些参数原样传给UsartPrintf。再加最后一句总纲这套日志宏不是在运行时决定“打不打印”而是在编译前决定“这行代码还在不在”。6. C / C 兼容包装在这些文件里很常见D:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\APP\cJSON.hD:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\Core\Inc\usart.hD:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\Core\Inc\gpio.h典型写法#ifdef__cplusplusexternC{#endif/* C 函数声明 */#ifdef__cplusplus}#endif6.1 作用如果这个头文件被 C 工程包含C 编译器会自动做名字修饰name mangling。这样会导致C 里实现的函数名和 C 编译器理解的函数名不一致最终链接失败。extern C的作用就是告诉 C这些函数按 C 的方式导出名字不要改名。6.2 为什么要用#ifdef __cplusplus因为在 C 编译器里__cplusplus根本不存在只有 C 编译器才会定义它所以这个条件编译的意思是如果当前是 C 编译就加extern C如果当前是 C 编译就什么都不加这是一种很典型的“跨语言兼容条件编译”。7. HAL 默认参数兜底位于D:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\Core\Inc\stm32f4xx_hal_conf.h典型写法#if!defined(HSE_VALUE)#defineHSE_VALUE25000000U#endif类似的还有HSI_VALUELSE_VALUELSI_VALUEHSE_STARTUP_TIMEOUTEXTERNAL_CLOCK_VALUE7.1 这类写法在干什么它是在做“有定义就用你的没有就给默认值”。也就是说如果你在工程选项或别的头文件里已经定义了HSE_VALUE那这里就不会重新定义如果你没定义这里才补一个默认值7.2 好处这种写法很适合做“通用配置模板”同一份 HAL 配置文件可以适应不同板子也允许上层工程覆盖默认值7.3 这和普通#define的区别普通#define HSE_VALUE ...是强制赋值。而#if!defined(HSE_VALUE)#defineHSE_VALUE...#endif是“未定义才赋值”更灵活也更安全。8. HAL 模块开关同样主要位于D:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\Core\Inc\stm32f4xx_hal_conf.h典型形式#ifdefHAL_GPIO_MODULE_ENABLED#includestm32f4xx_hal_gpio.h#endif还有很多类似HAL_RCC_MODULE_ENABLEDHAL_DMA_MODULE_ENABLEDHAL_UART_MODULE_ENABLEDHAL_TIM_MODULE_ENABLEDHAL_SPI_MODULE_ENABLEDHAL_I2C_MODULE_ENABLED8.1 作用这类条件编译是在控制某个 HAL 模块要不要参与编译某个头文件要不要被包含8.2 为什么这么做STM32 HAL 很大如果所有模块都打开编译更慢代码更大依赖更多所以 ST 的设计思路是先定义“启用哪些模块”再按宏去包含对应头文件和功能8.3 对你项目的意义你当前项目主要用到GPIOUARTTIMSPII2C所以 HAL 配置里这些启用宏直接决定底层库参与程度。9. 芯片型号和硬件能力判断这类多见于D:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\Core\Src\system_stm32f4xx.cCMSIS 头文件和驱动头文件例如常见会看到#ifdefined(STM32F407xx)...#endif或#if(__FPU_PRESENT1)(__FPU_USED1)...#endif9.1 作用根据不同芯片、不同硬件能力决定启动文件怎么配时钟树怎么配向量表位置怎么配FPU 要不要打开某些寄存器功能是否存在9.2 为什么必须用条件编译因为这些差异是“编译前就确定”的不是运行时才知道。比如你用的是STM32F407ZGT6它支持哪些外设、寄存器、FPU这些都取决于芯片型号这不是程序跑起来以后才能判断的事情所以必须用条件编译。10.defined(...)和#ifdef的关系你项目里两种都能看到。10.1#ifdef#ifdef__cplusplus...#endif等价于#ifdefined(__cplusplus)...#endif10.2#ifndef#ifndefLOG_LEVEL...#endif等价于#if!defined(LOG_LEVEL)...#endif10.3 什么时候用哪种经验上判断一个宏是否存在#ifdef/#ifndef更直观多条件组合判断#if defined(...) !defined(...)更灵活所以你会看到简单判断用#ifdef复杂判断用#if defined(...)11. 你的项目里“不是条件编译但容易误以为是”的内容比如很多地方有#definePASSWORD_MAX_COUNT12#defineSCREEN_MODE_FACE_RFID1#defineSERVO_UNLOCK_US2000这些不是条件编译。它们只是普通宏常量用来在编译前做文本替换。区别在于普通宏替换值条件编译决定代码保不保留所以#defineA10不是条件编译。而#ifA5...#endif才是条件编译。12. 头文件防重复包含现在再回头看这类写法就会更容易理解它为什么也是条件编译。例如D:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\APP\bsp_usart.hD:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\APP\serial_screen.hD:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\Core\Inc\main.h典型写法#ifndefBSP_USART_H#defineBSP_USART_H/* 头文件内容 */#endif12.1 它的作用防止同一个头文件被重复包含两次以上。比如main.c包含了bsp_system.hbsp_system.h又包含了bsp_usart.h另一个头文件也可能再次包含bsp_usart.h如果没有这层保护编译器就可能看到重复的类型定义重复的函数声明重复的宏定义然后报错。12.2 它为什么属于条件编译因为这里本质是在问BSP_USART_H这个宏定义过了吗如果没定义就编译头文件内容如果已经定义过就跳过整份头文件所以它虽然看起来像模板但本质仍然是条件编译。12.3 为什么这部分放到后面讲因为头文件保护更像一种“工程卫生习惯”。它当然很重要但它没有前面那些例子那么直接地体现“功能裁剪”和“编译前选代码”的味道。先理解日志等级、模块开关、芯片差异再回来看头文件保护会更容易把它放进整体框架里理解而不是只把它背成一个固定模板。13. 为什么单片机项目特别依赖条件编译你的这个毕设项目里条件编译非常合理原因包括13.1 资源有限STM32 的FlashRAM串口带宽调试时间都比较宝贵。所以像调试日志开关模块按需启用芯片特性差异裁剪这些都适合在编译阶段处理掉。13.2 同一份代码要兼容不同环境例如调试版 / 发布版C 编译 / C 编译不同晶振参数不同芯片型号这些差异最适合靠条件编译管理。13.3 比运行时判断更干净对于很多底层功能如果这个模块不用最好连代码都不要编进去而不是留着代码到运行时再判断不用。14. 你现在这个项目里最值得你自己掌握的条件编译点如果从“后面你自己维护项目”的角度看最值得掌握的是这 4 类14.1 日志等级文件D:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\APP\bsp_usart.h你最可能自己改的是#defineLOG_LEVEL1改成0只保留警告和错误1显示普通信息2连调试日志都显示14.2 HAL 模块开关文件D:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\Core\Inc\stm32f4xx_hal_conf.h这决定哪些 HAL 模块参与编译。14.3 晶振和超时参数默认值还是D:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\Core\Inc\stm32f4xx_hal_conf.h如果你以后换板子外部晶振不是当前值这一类就可能要跟着变。14.4 芯片型号宏一般由工程编译选项或 CMSIS 头文件体系决定比如STM32F407xx这类不要随便手改除非你真的换了芯片。15. 改条件编译时要特别小心什么15.1 不要把头文件保护删掉像#ifndefXXX_H#defineXXX_H...#endif这种看起来像模板但它是必须的。15.2 不要随便关 HAL 模块如果你把HAL_UART_MODULE_ENABLED之类的宏关掉可能会导致编译不过某些 HAL 头文件没包含某些底层函数声明消失15.3 不要误把条件编译当运行时逻辑例如日志宏改LOG_LEVEL会改变“编译出来的代码”不是程序运行时动态切换也就是说改了LOG_LEVEL后需要重新编译效果才会生效。15.4 芯片相关宏不要乱改像STM32F407xx__FPU_PRESENT__FPU_USED这类宏跟芯片和工具链配置绑定乱改会导致系统初始化异常甚至启动都不正常。16. 一个简单总结如果把你这个项目里的条件编译压缩成一句话可以这样理解条件编译就是“在编译之前用宏决定哪些代码存在哪些代码不存在”。在你的项目里它主要承担了这些职责控制日志输出等级做 C / C 兼容给 HAL 配置默认值按芯片能力启用或裁剪底层代码防止头文件重复包含所以条件编译不是“高级小技巧”而是嵌入式工程非常核心的一部分。17. 你后面可以怎么继续学如果你想把这一块真正吃透建议按这个顺序继续先彻底吃透#define、#ifdef、#ifndef、#if defined(...)再理解可变参数宏比如__VA_ARGS__然后学会区分编译时配置运行时状态最后再去看更复杂的跨平台头文件和 HAL / CMSIS 配置头18. 本项目里建议你重点查看的文件如果你想结合实际代码再读一遍最推荐这几个D:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\APP\bsp_usart.hD:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\APP\cJSON.hD:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\Core\Inc\stm32f4xx_hal_conf.hD:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\Core\Src\system_stm32f4xx.cD:\Desktop\STM32_Project_Collection\f407zgt6(hal)\Graduate_Project(物联网rfid正常通讯) -测试\Core\Inc\usart.h19. 最后一句最好记的话你可以先把条件编译记成下面这句话if是程序运行时做选择#if是编译器在编译前帮你删代码。这句话一旦真正理解了你后面再看 STM32、HAL、CMSIS 里的宏配置就会顺很多。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…