E906调试利器:printf重定向至UART的实现与优化
1. 为什么E906调试离不开printf重定向搞嵌入式开发的朋友都知道调试是开发过程中最耗时、也最让人头疼的环节。尤其是在像E906这样的RISC-V内核平台上开发初期硬件资源有限调试器Debugger可能还没完全调通或者手头根本就没有昂贵的仿真器。这时候我们最依赖的是什么就是最朴实无华的“打印大法”——printf。但问题来了在裸机环境或者刚移植好基础驱动的E906平台上你直接调用printf信息会输出到哪里答案是无处可去。标准的printf函数依赖于底层操作系统或库提供的输出通道比如在Linux下是终端在Windows下是控制台。但在我们的E906裸机工程里这个通道是缺失的所以printf要么不工作要么会导致程序卡死。所以**“printf重定向至UART”**就成了E906开发者的第一个“救命稻草”。它的核心思想很简单把printf这个高层、好用的格式化打印函数和我们手头已经调通的、最基础的硬件——UART串口——给连接起来。这样一来我们就能通过一根USB转串口线在电脑的串口助手上看到清晰的调试信息变量值、程序流程、错误标志……调试效率瞬间提升几个数量级。我刚开始接触E906时也在这上面绕了点弯路。网上资料要么太零碎只讲原理要么是其他平台如STM32的案例和E906的库结构对不上。后来摸索清楚了才发现整个过程就像给printf这个“大脑”接上一根“嘴巴”UART关键在于找到那个正确的连接点——fputc函数。一旦打通你会发现之前黑盒一样的芯片内部世界突然变得清晰可见。2. 深入原理printf是如何“说话”的在动手写代码之前我们得先搞明白printf到底是怎么工作的。这能帮你理解为什么要重写fputc而不是去改printf本身。你可以把printf想象成一个非常聪明的“排版师傅”。当你写下printf(Value: %d, Name: %s\n, num, str)时printf的核心工作分为两大步第一步格式化解析与拼接。printf会扫描字符串Value: %d, Name: %s\n当遇到%d和%s这样的格式控制符时它就会去后面可变参数列表里按照格式取出对应的整数num和字符串str。然后它把整数转换成可读的字符串再把所有部分Value: 、转换后的数字字符串、, Name: 、str字符串、换行符拼接成一个完整的、最终要输出的字符串。这个复杂的逻辑通常由一个叫vsnprintf或_vsnprintf的函数完成。在E906提供的C库源码里你也能找到类似的实现。第二步逐字输出。拼接好的完整字符串需要被送到某个“输出设备”上。为了最大程度的通用性适配屏幕、串口、文件、网络等不同设备C标准库设计了一个非常薄的底层接口fputc。它的功能极其单一——输出一个字符。printf或者说vsnprintf在完成格式化后就会循环调用fputc把长字符串一个一个字符地“吐”出去。所以整个调用链是这样的printf(...)-vsnprintf(...)-循环调用fputc(ch, stream)看到了吗fputc就是那个最终的、统一的出口。我们不需要去动printf或vsnprintf那些复杂的格式化逻辑那是经过千锤百炼的代码我们只需要“劫持”这个最底层的fputc告诉它“别用默认的方式了请把我给你的每一个字符都通过UART串口发出去。”这就是重定向的全部哲学在保持上层接口printf完全不变的情况下通过定制底层实现fputc来改变输出目的地。3. 动手第一步配置好你的UART硬件驱动兵马未动粮草先行。想让printf从UART输出前提是你的UART本身能正常工作。这里以E906常见的开发环境为例分享一下UART初始化的关键步骤和容易踩的坑。首先你需要确认手头E906芯片的UART外设基地址和时钟源。这些信息通常在芯片的数据手册Datasheet或评估板原理图中。假设我们使用UART0。一个完整的UART初始化流程通常包含以下几个关键步骤我把它总结成一个配置清单引脚复用配置确认UART的TX发送和RX接收引脚是否正确映射到芯片的物理引脚上。有些芯片需要通过GPIO复用功能寄存器来设置。时钟使能打开UART模块的时钟门控否则寄存器访问可能无效。波特率设置这是最核心的参数。需要根据系统主频和期望的波特率如115200来计算分频系数并写入相应的寄存器。计算错误会导致乱码。数据帧格式配置包括数据位通常8位、停止位通常1位、奇偶校验位通常无校验。发送/接收使能开启UART的发送器和/或接收器。在E906的SDK或例程中这些步骤往往被封装成了一个初始化函数。比如你可能看到一个类似ck_uart_init的函数。你需要重点关注它需要的配置结构体。下面是一个典型的配置过程#include uart.h // 包含UART驱动头文件 // 声明一个UART设备结构体通常SDK会要求你定义一个全局或静态变量 t_ck_uart_device uart0; int uart_init_for_printf(void) { t_ck_uart_cfig uart_cfig; // 1. 填充配置参数 uart_cfig.baudrate 115200; // 波特率根据你的调试终端设置 uart_cfig.parity PARITY_NONE; // 无奇偶校验 uart_cfig.stopbit STOPBIT_1; // 1位停止位 uart_cfig.wordsize WORDSIZE_8; // 8位数据位 uart_cfig.txmode ENABLE; // 使能发送这是printf输出必需的 // 2. 打开UART设备假设UART0的设备ID是0 if (ck_uart_open(uart0, 0) ! 0) { // 处理错误可能是设备ID不对或硬件故障 return -1; } // 3. 根据配置初始化UART if (ck_uart_init(uart0, uart_cfig) ! 0) { // 处理错误配置不支持或波特率计算溢出 return -2; } // 4. 可选但推荐发送一个测试字符串验证UART本身是否通畅 const char *test_msg UART Init OK!\r\n; while (*test_msg) { ck_uart_putc(uart0, *test_msg); } return 0; // 初始化成功 }实测经验分享波特率对齐务必确保代码里设置的波特率和电脑上串口调试助手如Putty、SecureCRT、MobaXterm的串口功能选择的波特率完全一致差一点都会导致乱码。硬件连接TX接RXRX接TXGND接GND这是老生常谈但最容易接错的地方。上电顺序有时先给开发板上电再打开电脑上的串口软件能避免接收到一些上电瞬间的乱码。如果发现第一次上电没输出可以尝试按一下板子的复位键。驱动安装确保USB转串口芯片的驱动如CH340、CP2102、FT232已在电脑上正确安装设备管理器中能正确识别到COM口。当你在串口助手看到“UART Init OK!”这行字时恭喜你最基础的硬件通道已经打通了我们可以开始给printf接上这根“管子”了。4. 核心实现重写fputc函数UART调通了现在就来完成最核心的一步实现我们自己的fputc。这个过程简单到令人惊喜但细节决定成败。C标准库中fputc的函数原型是这样的int fputc(int ch, FILE *stream);ch要输出的字符以整型传递。stream指向文件流的指针。对于标准输出stdout这个流是预定义的。返回值成功时返回写入的字符失败时返回EOF。在我们的重定向版本里我们几乎可以忽略stream参数但为了兼容性必须保留只关心ch。我们的任务就是把ch交给UART发送函数。假设UART发送单字节的函数是ck_uart_putc那么最简单的实现如下// 重写fputc实现printf到UART的重定向 int fputc(int ch, FILE *stream) { // 将字符通过UART0发送出去 ck_uart_putc(uart0, (char)ch); // 注意必须将字符转换为char类型有些UART驱动要求char* // 非常重要如果输出的是\n换行通常我们需要添加\r回车 // 这样在串口终端上才能正确换行 if (ch \n) { ck_uart_putc(uart0, \r); } // 标准要求返回写入的字符 return ch; }把这段代码放在你的主程序文件如main.c里放在所有函数定义的前面或者放在一个单独的my_fputc.c文件中并在头文件里声明。关键是要让编译器在链接时使用我们这个版本的fputc而不是标准库里的那个弱定义版本。这里有几个至关重要的优化点和坑我踩过希望你避开换行符处理\n vs \r\n这是新手最容易困惑的地方。在C语言字符串里\n表示“换行”。但在Windows系统的串口终端和许多网络协议中“新起一行”需要两个字符回车\r让光标回到行首和换行\n让光标移到下一行即\r\n。而Linux/Unix风格的终端通常只需要\n。为了最大兼容性强烈建议在fputc里做判断如果收到\n就额外发送一个\r。这样无论在哪种串口助手上显示都会整齐。发送阻塞与缓冲区ck_uart_putc这个函数可能是“阻塞式”的即它会一直等待直到UART发送缓冲区空闲才把字符放进去。这保证了数据不会丢失但也意味着如果UART故障程序可能会卡死在这里。在调试初期这反而是个优点能立刻发现问题。如果你的驱动提供了非阻塞或带超时的发送函数在稳定性要求高的场景可以考虑使用但调试阶段用阻塞式最简单可靠。多个UART的选择如果你的系统有多个UART比如UART0用于调试UART1连接蓝牙模块你可以在fputc里通过判断某个全局标志来决定将printf输出到哪个端口实现动态切换调试输出目标非常灵活。5. 解决工程中的“多定义”冲突按照上面的步骤写好fputc满怀期待地编译工程你可能会遇到一个链接错误multiple definition of fputcfputc多重定义。这是因为在E906的SDK或你使用的C库中很可能已经存在一个默认的、弱定义的fputc函数。这个默认函数可能是一个空函数或者指向一个无效的输出。链接器发现了两个同名的强符号不知道用哪个。解决这个问题通常有两种方法方法一注释或删除库中的默认实现直接有效就像原始文章里提到的去工程目录里找到那个默认的fputc实现文件。根据原始文章的提示路径可能是opene906-main/smart_run/tests/lib/clib/fputc.c。用编辑器打开这个文件找到fputc函数将其内容注释掉。// int fputc(int ch, FILE *stream) // { // // 原来的空实现或桩函数 // return 0; // }然后重新编译。这是最彻底的方法确保链接器只找到你写的那一个fputc。方法二利用编译链接顺序更规范如果你不想修改库文件或者库文件是只读的可以通过调整编译链接顺序来让链接器优先使用你的版本。在Makefile或CMakeLists.txt中确保包含你my_fputc.c文件的源文件列表放在链接库-lxxx的前面。因为链接器是按顺序处理输入文件的遇到符号时先用先找到的。# 在链接命令中你的.o文件放在前面 $(CC) ... obj/main.o obj/my_fputc.o ... -lck_uart -lc ...同时确保你的fputc函数定义是“强符号”。简单来说就是正常地定义函数不要加__attribute__((weak))这样的弱属性修饰。我个人的习惯是使用方法一一劳永逸并且能在源码层面明确知道我们覆盖了默认行为。修改后清理工程make clean再重新编译make之前的链接错误就应该消失了。6. 完整示例与效果验证理论说了这么多我们来一个“全家桶”式的代码示例把前面所有步骤串起来形成一个可以直接编译测试的main.c模板。/** * E906 printf重定向至UART0 完整示例 */ #include datatype.h #include stdio.h #include uart.h // 全局UART设备结构体 t_ck_uart_device uart0; // 简单的毫秒级延时函数用于演示实际应用建议使用定时器 void delay_ms(int time) { volatile int i, j; // 加volatile防止被优化掉 for (i 0; i time; i) { for (j 0; j 50000; j) { // 这个循环次数需要根据你的CPU频率调整 // 空循环 } } } // 核心重写的fputc函数 int fputc(int ch, FILE *stream) { // 发送字符到UART0 ck_uart_putc(uart0, (char)ch); // 关键优化为换行符添加回车确保终端显示整齐 if (ch \n) { ck_uart_putc(uart0, \r); } return ch; } int main(void) { int counter 0; float voltage 3.3f; char *message Debug from E906; // --- UART初始化配置 --- t_ck_uart_cfig uart_cfig; uart_cfig.baudrate 115200; uart_cfig.parity PARITY_NONE; uart_cfig.stopbit STOPBIT_1; uart_cfig.wordsize WORDSIZE_8; uart_cfig.txmode ENABLE; // 必须使能发送 // 打开并初始化UART0 if (ck_uart_open(uart0, 0) ! 0) { // 这里可以点亮一个LED表示错误但既然printf还不能用... while(1); // 死循环方便发现故障 } ck_uart_init(uart0, uart_cfig); // 发送一个初始化成功标志直接调用UART函数不依赖printf const char *init_msg \r\n*** System Boot ***\r\n; while (*init_msg) { ck_uart_putc(uart0, *init_msg); } // --- 现在可以愉快地使用printf了 --- printf(UART and printf redirect is ready!\r\n); printf(\r\n); while (1) { // 示例1打印基本信息和变量 printf([%04d] Main loop running...\r\n, counter); // 示例2打印浮点数需要确保库支持 printf( - ADC Voltage: %.2f V\r\n, voltage); // 示例3打印字符串和地址便于观察指针 printf( - Message: %s (ptr: %p)\r\n, message, message); // 示例4简单的进度条或状态指示 printf( - Status: [); for (int i 0; i 10; i) { if (i (counter % 10)) { printf(#); } else { printf( ); } } printf(]\r\n\r\n); // 两个换行让输出更清晰 // 更新变量模拟程序运行 counter; voltage 0.01f; if (voltage 5.0f) voltage 0.0f; // 延时避免输出刷屏太快 delay_ms(500); } return 0; // 实际上裸机程序不会返回这里 }将这段代码编译、下载到E906开发板并打开串口助手设置波特率1152008N1你应该能看到类似下面的滚动输出*** System Boot *** UART and printf redirect is ready! [0000] Main loop running... - ADC Voltage: 3.30 V - Message: Debug from E906 (ptr: 0x20001000) - Status: [ ] [0001] Main loop running... - ADC Voltage: 3.31 V - Message: Debug from E906 (ptr: 0x20001000) - Status: [# ] ...看到这样结构清晰、带变量值、带格式的调试信息源源不断地输出是不是感觉调试的主动权完全掌握在自己手里了这比点灯大法高级多了程序内部的所有状态变化都一目了然。7. 高级优化与实战技巧基础功能实现后我们可以追求更高效、更稳定的调试输出。下面分享几个我在实际项目中用到的优化技巧。1. 添加互斥锁防止多任务/中断打断如果你的程序使用了RTOS或多任务或者printf可能在中断服务程序ISR中被调用那么直接调用ck_uart_putc是危险的。因为UART发送函数可能不是可重入的多个任务同时调用fputc会导致输出信息交错混乱比如一个任务的数字插到另一个任务的字符串里。解决方案是在fputc里加入简单的互斥保护。对于无RTOS但有中断的场景可以在发送前关中断发送后再开中断。对于有RTOS的场景可以使用信号量Semaphore或互斥量Mutex。// 示例用于无RTOS但需防止中断打断的简单保护 int fputc(int ch, FILE *stream) { uint32_t primask; // 用于保存中断状态 int ret_val ch; // 保存当前中断状态并关闭全局中断 primask disable_global_irq(); // 发送字符 ck_uart_putc(uart0, (char)ch); if (ch \n) { ck_uart_putc(uart0, \r); } // 恢复之前的中断状态 restore_global_irq(primask); return ret_val; }注意disable_global_irq和restore_global_irq需要你根据E906的内核中断控制寄存器来实现。关中断时间要尽可能短只保护UART发送操作。2. 实现printf的宏封装方便开关调试信息在项目后期调试信息可能太多影响性能或刷屏。我们可以定义一个宏来灵活开关printf。// 在公共头文件如debug.h中定义 #define DEBUG_ENABLE 1 // 1:开启调试 0:关闭调试 #if DEBUG_ENABLE #define DEBUG_PRINTF(...) printf(__VA_ARGS__) #else #define DEBUG_PRINTF(...) // 定义为空编译器会优化掉 #endif // 在代码中使用 DEBUG_PRINTF(This is debug info: %d\r\n, value); // 只有DEBUG_ENABLE为1时才会被编译和输出更进一步可以定义不同等级的调试信息#define LOG_LEVEL_ERROR 1 #define LOG_LEVEL_WARN 2 #define LOG_LEVEL_INFO 3 #define LOG_LEVEL_DEBUG 4 #define CURRENT_LOG_LEVEL LOG_LEVEL_DEBUG #define LOG_E(...) if(CURRENT_LOG_LEVEL LOG_LEVEL_ERROR) {printf([E] ); printf(__VA_ARGS__);} #define LOG_W(...) if(CURRENT_LOG_LEVEL LOG_LEVEL_WARN) {printf([W] ); printf(__VA_ARGS__);} #define LOG_I(...) if(CURRENT_LOG_LEVEL LOG_LEVEL_INFO) {printf([I] ); printf(__VA_ARGS__);} #define LOG_D(...) if(CURRENT_LOG_LEVEL LOG_LEVEL_DEBUG) {printf([D] ); printf(__VA_ARGS__);}3. 处理浮点数打印%f有些为嵌入式优化的C库如newlib-nano默认禁用了浮点数格式化支持以节省代码空间。如果你使用%f或%g时发现程序崩溃或输出异常如%f直接输出f字符就需要在链接时显式地启用浮点支持。 在Makefile的链接标志LDFLAGS中加上-u _printf_float或者使用newlib的完整版而不是nano版。这会使编译出的固件体积增大但换来了方便的浮点调试能力在需要精确查看传感器数据如温度、电压时非常有用。4. 输出到多个目的地有时你可能想同时将日志保存到文件系统如SD卡和输出到串口。可以在fputc里实现一个简单的“多路复用”int fputc(int ch, FILE *stream) { char c (char)ch; // 1. 始终输出到UART调试 ck_uart_putc(uart0, c); if (c \n) ck_uart_putc(uart0, \r); // 2. 同时输出到文件如果文件系统已就绪 if (log_file_is_open()) { file_write_char(log_file, c); // 文件系统通常自己处理换行这里不需要额外加\r } // 3. 甚至可以输出到网络或LCD根据需求 // ... return ch; }掌握了这些基础实现和优化技巧printf重定向就不再是一个简单的调试功能而是一个可以根据项目需求灵活定制、稳定可靠的日志输出系统。它将成为你在E906乃至所有嵌入式平台上最得心应手的开发利器。下次当你遇到程序行为诡异时别犹豫多打几个printf让芯片亲自告诉你它正在想什么。

相关新闻

RMBG-1.4在跨境电商中的应用:AI净界批量生成多国商品主图素材

RMBG-1.4在跨境电商中的应用:AI净界批量生成多国商品主图素材

RMBG-1.4在跨境电商中的应用:AI净界批量生成多国商品主图素材 1. 项目背景与核心价值 跨境电商卖家每天都要面对一个共同的痛点:商品图片处理。不同国家、不同平台的商品主图要求各不相同,但传统修图方式效率低下,成本高昂。 一…

2026/5/17 5:31:35 阅读更多 →
如何夺回数字记忆主权?GetQzonehistory让社交数据回归用户掌控

如何夺回数字记忆主权?GetQzonehistory让社交数据回归用户掌控

如何夺回数字记忆主权?GetQzonehistory让社交数据回归用户掌控 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 当你十年前在QQ空间写下的青春感悟突然无法访问,当…

2026/5/17 5:31:35 阅读更多 →
DeepSeek-R1-Distill-Qwen-7B快速入门:零基础也能轻松上手

DeepSeek-R1-Distill-Qwen-7B快速入门:零基础也能轻松上手

DeepSeek-R1-Distill-Qwen-7B快速入门:零基础也能轻松上手 1. 引言 你是不是对AI大模型充满好奇,但又觉得技术门槛太高?今天我要介绍的DeepSeek-R1-Distill-Qwen-7B,就是一个让零基础用户也能轻松上手的智能模型。这个模型特别适…

2026/5/17 5:31:35 阅读更多 →

最新新闻

常见排序算法详解

常见排序算法详解

一、插入排序插入排序的核心思想是把一个数据插入已经排好序的一组数据中的正确位置。当运用插入排序来排序一组数据时,先把第一个数看作有序,把第二个数插入正确位置;再把前两个数看作有序,把第三个数插入正确位置,以…

2026/7/5 14:12:18 阅读更多 →
网络安全人才缺口327万!应急响应工程师薪资涨幅领跑IT行业,你上车了吗

网络安全人才缺口327万!应急响应工程师薪资涨幅领跑IT行业,你上车了吗

327万缺口,安全行业的人才荒2026年,中国网络安全行业面临着一个令人既兴奋又焦虑的数字:327万。这是教育部、工业和信息化部联合发布的《网络安全人才发展报告》中披露的最新人才缺口数字。与此同时,全国高校每年网络安全相关专业…

2026/7/5 14:12:18 阅读更多 →
【信息科学与工程学】【制造工程】第八十二篇 半导体芯片集成电路集成制造01

【信息科学与工程学】【制造工程】第八十二篇 半导体芯片集成电路集成制造01

半导体芯片集成制造 编号 类型 领域 子领域 / 内容 问题 步骤拆解 参数列表及参数的数值范围及数值分析及常量/常数 1 物理制造 光刻 Lithography 光学成像 + OPC 掩模图案经投影物镜后在光刻胶上形成畸变,如何预补偿? 电磁(亥姆霍兹/波动光学)+ 傅里叶光学 +…

2026/7/5 14:12:18 阅读更多 →
Windows系统优化新选择:Winhance中文版如何让电脑重获新生?

Windows系统优化新选择:Winhance中文版如何让电脑重获新生?

Windows系统优化新选择:Winhance中文版如何让电脑重获新生? 【免费下载链接】Winhance-zh_CN A Chinese version of Winhance. C# application designed to optimize and customize your Windows experience. 项目地址: https://gitcode.com/gh_mirror…

2026/7/5 14:08:17 阅读更多 →
Leetcode新动循环嵌套之数组异或操作、好数对的数目、统计好三元组

Leetcode新动循环嵌套之数组异或操作、好数对的数目、统计好三元组

1486.数组异或操作class Solution:def xorOperation(self, n: int, start: int) -> int:nums []for i in range(n):nums.append(start 2*i)resultnums[0]for i in range(1,n):result ^ nums[i]return result1512.好数对的数目class Solution:def numIdenticalPairs(self,…

2026/7/5 14:06:16 阅读更多 →
[特殊字符] Oracle EBS 中国客户(校正版)华为确实是 Oracle EBS 的老客户,不是 SAP。时间线先给你对齐:华为 1996 年引入 MRP Ⅱ,之后 20 多年核心 ERP 是

[特殊字符] Oracle EBS 中国客户(校正版)华为确实是 Oracle EBS 的老客户,不是 SAP。时间线先给你对齐:华为 1996 年引入 MRP Ⅱ,之后 20 多年核心 ERP 是

🟢 Oracle EBS 中国客户(校正版)华为确实是 Oracle EBS 的老客户,不是 SAP。时间线先给你对齐:华为 1996 年引入 MRP Ⅱ,之后 20 多年核心 ERP 是 Oracle EBS,支撑全球 170 国家、每年数千亿产值…

2026/7/5 14:06:16 阅读更多 →

日新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻