C++代码调试技巧:面试官问“你的程序崩了怎么排查“,别只说printf
上篇聊了CMake把项目的编译构建搞明白了。今天说编译之后的事——调试。先讲个面试场景。面试官问你的机器人程序跑着跑着突然segfault了你怎么排查我当时脱口而出加printf看哪里挂了。面试官没说话就看着我。我接着补充也可以用日志……场面一度很尴尬。后来才知道面试官想听的不是这个。他想听的是系统性的排查思路——core dump分析、GDB定位崩溃点、ASAN检测内存问题、日志系统辅助定位。这几个工具的组合使用才是一个成熟的C开发者应该具备的调试能力。GDBC调试的瑞士军刀GDB是Linux下最强大的调试器。虽然用起来不如IDE的调试器直观但在服务器环境和机器人本体上你通常只能通过命令行调试。基本操作大家都知道break设断点run运行next单步continue继续print打印变量。这些是入门级的。真正有用的是几个进阶用法。第一个是core dump分析。程序崩溃后系统会生成一个core文件记录了崩溃时的内存状态。用GDB加载它gdb ./my_robot_node core进去之后输入btbacktraceGDB会告诉你崩溃时的函数调用栈。比如#0 0x00005555 in LidarProcessor::processScan (this0x0, scan...) #1 0x00005678 in PerceptionModule::update (this0x55555...) #2 0x00005890 in main ()一眼就能看到LidarProcessor的this指针是0x0空指针解引用。问题定位到了。要注意生成core dump需要系统配置。默认情况下Ubuntu的core dump大小限制是0。需要执行ulimit -c unlimited或者配置systemd的coredump handler。面试的时候如果能提到这个细节加分。第二个是条件断点。在循环里某个特定条件才触发的问题不可能手动一步步走到那个条件。用条件断点break sensor.cpp:42 if distance 0.01只有当distance小于0.01时才会停下来。这在调试数值计算问题时特别有用。第三个是watchpoint。你想观察某个变量什么时候被修改了watch robot_state每次robot_state被写入程序都会暂停。找那种不知道谁改了全局变量的bug时watchpoint是神器。ASAN内存问题的照妖镜GDB擅长定位崩溃现场但有些内存问题不会立刻崩溃——它们像定时炸弹不知道什么时候炸。比如堆缓冲区溢出写数据时越界了一个字节use-after-free对象被delete了还在用内存泄漏new了没delete栈溢出递归太深或者局部变量太大这些问题GDB不一定能抓到。但AddressSanitizerASAN可以。ASAN是编译器内置的内存检测工具。用法非常简单编译时加两个flagset(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -fsanitizeaddress -g) set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} -fsanitizeaddress)然后正常运行程序。一旦发生内存问题ASAN会立刻终止程序并输出详细的错误报告精确到文件、行号告诉你那块内存是什么时候分配、什么时候释放的。ASAN的性能开销大概是2倍左右。所以一般只在Debug模式下开Release发布时关掉。在机器人项目里我建议在CI里加一个ASAN的构建配置每次提交自动跑一遍测试。除了AddressSanitizer还有ThreadSanitizer检测数据竞争、MemorySanitizer检测未初始化内存、LeakSanitizer检测内存泄漏。用法都一样换个flag就行。面试的时候如果能提一嘴这些工具的区别和适用场景说明你确实有实际调试经验。日志系统生产环境的调试手段ASAN和GDB都适合开发阶段。但程序部署到机器人上跑的时候你不可能挂着GDB。这时候日志就是最重要的调试手段。很多新手用std::cout打日志。这在本地demo里够用但在真实项目里问题很多没有级别控制、没有文件输出、多线程下输出会交错。工业级的做法是用日志库。C常用的有spdlog和glog。spdlog速度快、API友好是目前最流行的选择#include spdlog/spdlog.h int main() { spdlog::info(Robot node started); spdlog::error(Sensor processing failed: {}, e.what()); }日志的级别很重要。DEBUG级别的日志在发布时关掉INFO记录关键流程WARN记录异常但可恢复的情况ERROR记录严重错误。通过配置文件或者运行时参数调整日志级别不需要重新编译。在ROS2里每个节点自带日志系统rclcpp::get_logger()。用法类似RCLCPP_INFO(this-get_logger(), Lidar scan received, %zu points, scan.points.size()); RCLCPP_ERROR(this-get_logger(), Failed to connect to lidar);日志输出会自动加上节点名、时间戳和日志级别。在多节点的机器人系统里这个前缀信息对于区分日志来源非常关键。还有一个实用技巧在关键路径上加带上下文的日志。比如处理传感器数据之前记录数据的大小和时间戳处理之后记录结果的摘要。出了问题翻日志就能定位到是哪一步出的问题。几个实战排查思路面试里还有一个经常被追问的细节内存泄漏怎么排查除了ASANValgrind是经典工具。valgrind --leak-checkfull ./your_program能告诉你每一处未释放的内存分配点和调用栈。缺点是运行速度会慢几十倍不适合实时性要求高的程序。实际项目中我一般先用ASAN快速筛查确认有泄漏后再用Valgrind定位具体位置。还有一个实用技巧GDB的watch命令可以监控变量变化。比如你怀疑某个指针被意外修改设置watch ptr当ptr的值发生变化时程序会自动暂停然后你用bt查看调用栈就能看到是谁修改了这个指针。这在排查多线程环境下的野指针问题时特别有用。面试的时候面试官问程序崩了怎么排查他期望的是一个完整的思路而不是零散的工具名。第一步看core dump。用GDB加载bt看调用栈info locals看局部变量定位崩溃点。第二步如果崩溃点和内存有关segfault、double free开ASAN重跑让ASAN告诉你具体的内存错误类型。第三步如果问题不是崩溃而是逻辑错误输出不对、行为异常加日志缩小范围。在关键函数的入口和出口打日志二分法缩小问题区间。第四步如果是多线程问题偶发崩溃、数据不一致用ThreadSanitizer检测数据竞争或者用GDB的thread apply all bt看所有线程的调用栈。第五步如果问题只在特定环境出现对比两个环境的差异——库版本、编译选项、硬件配置。这个排查流程有条理地讲出来比单纯说我用GDB调强太多了。给正在准备面试的你调试能力这个东西很难通过看书学会。你得真的遇到bug真的去调才能积累经验。建议你在做项目的时候故意给自己制造一些bug——写个越界访问、写个空指针、写个多线程数据竞争——然后用上面这些工具去定位。经历过几次之后面试的时候讲起来就有底气了。下篇聊C性能优化实战——profile驱动优化的完整流程。代码能跑了还得跑得快。怎么找到性能瓶颈、怎么优化这是面试中区分初级和高级开发者的话题。如果这篇文章对你有帮助欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。「机器人软件开发面试·从入门到精通」连载系列上一篇第63篇 CMake编译系统详解——从入门到能写复杂项目 下一篇预告第65篇 C性能优化实战——profile驱动优化的完整流程有任何问题欢迎评论区留言我会尽量回复。

相关新闻

3分钟搭建数字商品自动化售货系统:独角数卡完整指南

3分钟搭建数字商品自动化售货系统:独角数卡完整指南

3分钟搭建数字商品自动化售货系统:独角数卡完整指南 【免费下载链接】dujiaoka 🦄独角数卡(自动售货系统)-开源站长自动化售货解决方案、高效、稳定、快速!🚀🚀🎉🎉 项目地址: https://gitcod…

2026/8/30 18:31:48 阅读更多 →
3分钟搞定黑苹果EFI配置:OpCore Simplify让复杂配置变简单

3分钟搞定黑苹果EFI配置:OpCore Simplify让复杂配置变简单

3分钟搞定黑苹果EFI配置:OpCore Simplify让复杂配置变简单 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 你是否曾经为黑苹果的EFI配置感…

2026/8/20 12:47:43 阅读更多 →
3个关键功能让老旧Mac也能轻松制作Windows启动盘:WinDiskWriter深度解析

3个关键功能让老旧Mac也能轻松制作Windows启动盘:WinDiskWriter深度解析

3个关键功能让老旧Mac也能轻松制作Windows启动盘:WinDiskWriter深度解析 【免费下载链接】windiskwriter 🖥 Windows Bootable USB creator for macOS. 🛠 Patches Windows 11 to bypass TPM and Secure Boot requirements. 👾 UE…

2026/9/2 18:25:45 阅读更多 →

最新新闻

Git 源码仓库全景指南:定位、构建安装、版本机制、文档体系与贡献工作流

Git 源码仓库全景指南:定位、构建安装、版本机制、文档体系与贡献工作流

Git 源码仓库全景指南:定位、构建安装、版本机制、文档体系与贡献工作流 【免费下载链接】git Git Source Code Mirror - This is a publish-only repository but pull requests can be turned into patches to the mailing list via GitGitGadget (https://gitgitg…

2026/9/4 14:07:55 阅读更多 →
零基础学Python · 第 20 课|列表常用方法与内置函数

零基础学Python · 第 20 课|列表常用方法与内置函数

进行分类、、实施复制这样的一套动作, 进行求和、求最大值、求最小值、计算长度这四大类操作。 20.1 原地方法 vs 新列表函数 原地 vs 新建 nums [3, 1, 4, 1, 5] # 方法大多"原地修改": 改自己, 返回 None nums.sort() # 排序后 nums 变了, 但 sor…

2026/9/4 14:07:55 阅读更多 →
Python遍历数组还在for循环?这招快10倍,代码直接起飞

Python遍历数组还在for循环?这招快10倍,代码直接起飞

数组遍历全解析于编程之时, 用以表示数组的通常是列表list, 此为一种极为常见的数据结构。对数组开展遍历操作, 乃是日常编程里常常会碰到的任务。它能让我们逐个去访问数组中的元素, 之后做相应处理。本文会把有关数组遍历的基础概念、使用方法、常见实践以及最佳实践予以详细…

2026/9/4 14:07:55 阅读更多 →
C语言基础:从文件概念到输入输出函数

C语言基础:从文件概念到输入输出函数

目录一、C语言中文件的相关概念二、C语言中的变量三、C语言中的常量四、定义常量五、进制转换六、输入输出函数一、C语言中文件的相关概念在C语言中分为三种文件:源文件(.c)、头文件(.h)和库文件(系统中&am…

2026/9/4 14:07:55 阅读更多 →
基于Zynq的FPGA开发:Vitis工程搭建与UART/GPIO实战

基于Zynq的FPGA开发:Vitis工程搭建与UART/GPIO实战

从近似0基础开始FPGA开发 -- part.5 Vitis工程搭建(Uart及GPIO)前几篇我们把Vivado里的硬件工程搭了起来,Block Design里也把Zynq PS核配好,并且导出了xsa硬件描述文件。但说实话,到这一步,很多刚开始接触Z…

2026/9/4 14:06:55 阅读更多 →
linux系统操作

linux系统操作

含义:查看当前时间 date 含义:查看系统盘磁盘空间占用大小 df -h 含义:端口监听信息查看 netstat -lntp netstat -lntp | grep 80 含义:查看哪个进程在监听80端口 netstat -lntp | grep nginx 含义:查看nginx监听的…

2026/9/4 14:06:55 阅读更多 →

日新闻

ESP32S2嵌入式收音机全栈开发实战指南

ESP32S2嵌入式收音机全栈开发实战指南

简介:本资源是一个基于ESP32-S2芯片的嵌入式综合实践项目,面向本科毕业设计、课程设计及实训开发人员,聚焦网络收音机与FM收音机双模功能实现,融合ESP-IDF框架、ESP-ADF音频开发库与LVGL图形界面库,具备完整软硬件协同…

2026/9/4 0:00:28 阅读更多 →
WorkBuddy+Python实战:从零搭建商品库存管理系统

WorkBuddy+Python实战:从零搭建商品库存管理系统

最近想自己动手做一个“商品库存管理系统”的人变多了。很多开网店、做小团队ERP选型、或者刚学Python的读者,不是不想用系统,而是被传统开发路径劝退了:要装数据库,要写后端接口,要学前端页面,还要考虑多人…

2026/9/4 0:00:28 阅读更多 →
旅游情感分析:基于Python的垂直场景深度解析

旅游情感分析:基于Python的垂直场景深度解析

简介:本资源是一份面向计算机专业本科生的毕业设计实践项目,聚焦旅游行业真实场景,解决旅游平台对用户评论情感倾向自动识别与管理的需求。系统基于Python 3.9.11与Anaconda环境构建,集成携程、马蜂窝双平台爬虫模块,并…

2026/9/4 0:00:28 阅读更多 →

周新闻

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

每年校招季我都会接触不少准备数据库方向笔试的同学,看到最多的状态就是:简历上写着“熟悉 MySQL”“了解索引优化”,一碰到数据库管理工程师的笔试卷,却在索引、事务、锁、备份恢复这些题目上翻车。网易这套 2018 校园招聘数据库…

2026/9/4 10:54:27 阅读更多 →
数字电路时序基石:深入理解建立时间与保持时间

数字电路时序基石:深入理解建立时间与保持时间

1. 这不是“背公式”的事:时间参数到底在约束什么你翻过数字电路教材,一定见过这两个词:建立时间(Setup Time)和保持时间(Hold Time)。它们常被并列写在触发器(Flip-Flop&#xff09…

2026/9/3 4:22:01 阅读更多 →
蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

1. 项目缘起:从赛题到超声波测距机的诞生第八届蓝桥杯单片机设计与开发国赛的题目,我至今记忆犹新。它没有直接给出一个花哨的名字,而是用“超声波测距机”这个朴实无华的功能描述,精准地勾勒出了考核的核心。对于当时备赛的我而言…

2026/9/3 4:22:59 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/3 4:17:49 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/3 4:18:56 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/4 9:37:01 阅读更多 →