Ubuntu下VSCode调试C程序时fopen函数异常问题排查
问题:Ubuntu下VSCode调试C程序时fopen单步进入异常退出
我在Ubuntu系统下使用VSCode编写C程序,代码实际功能为将文件最后一行打印到stdout(顶部注释描述的功能与实际不符,本次问题与功能无关):
/* Usage: ./reverse [input] [output] Algorithm: Builds a linked list of strings, each for a line in [input], and then walk the nodes backward to build the [output] */ #include "stdio.h" #include "stdlib.h" #include <stdint.h> #include <stdbool.h> int main(int argc, char* argv[]) { if (argc != 2) { printf("Usage: ./reverse [filename]\n"); exit(EXIT_FAILURE); } // breakpoint set at next line char* filename = argv[1]; FILE* fp = fopen(filename, "r"); if (fp == NULL) { printf("Cannot open file %s\n", filename); exit(EXIT_FAILURE); } // StackOverflow users please ignore the rest of the code // fseek() to the end of file and move back to find EOL int64_t offset = 1; int64_t offsetNextEOL = 0; int64_t offsetThisEOL = 0; while (true) { if (fseek(fp, -offset, SEEK_END) != 0) { fprintf(stderr, "fseek() error\n"); } else { char ch = fgetc(fp); if (ch == '\n') { // print the last line to stdout offsetThisEOL = ftell(fp); if (offsetNextEOL < offsetThisEOL) { // We just found the last EOL so print everything from it to EOF if (fseek(fp, 0, SEEK_END) != 0) { fprintf(stderr, "fseek() error\n"); } int64_t offsetEOF = ftell(fp); int64_t offsetDiff = offsetEOF - offsetThisEOL; // Now seek back to offsetThisEOL and start print if (fseek(fp, -offsetThisEOL, SEEK_END) != 0) { fprintf(stderr, "fseek() error\n"); } for (int64_t i = 0; i < offsetDiff; i++) { printf("%c", fgetc(fp)); } // For the last line, no need to print EOL // We just found the last EOL so need to set up offsetNextEOL offsetNextEOL = offsetThisEOL; } break; } } offset++; } exit(EXIT_SUCCESS); }
目录结构如下(所有文件在同一文件夹):
-os -.vscode -utils reverse.c reverse reverse.txt
我的launch.json配置如下:
{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", "program": "${workspaceRoot}/utils/reverse", "cwd": "${workspaceRoot}/utils", "args": ["reverse.txt"], "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true }, { "description": "Set Disassembly Flavor to Intel", "text": "-gdb-set disassembly-flavor intel", "ignoreFailures": true } ] } ] }
我在char* filename = argv[1];行设置了断点,调试时发现执行到fopen()函数,单步进入后调试器仅闪三下,无任何特殊提示便以代码0退出。我猜测是路径问题但无法定位,请问问题出在哪里?
解决方案
1. 确保编译时添加调试信息
编译程序时必须加上-g参数,否则gdb无法正确解析标准库函数的调试信息,单步进入时会出现异常退出。正确的编译命令为:
gcc -g reverse.c -o reverse
2. 安装libc调试符号
Ubuntu默认未安装标准库的调试符号,导致gdb无法进入fopen等系统函数。执行以下命令安装:
sudo apt-get install libc6-dbg
安装完成后重新调试,即可正常单步进入标准库函数。
3. 验证文件路径与权限
虽然配置中设置了cwd为${workspaceRoot}/utils,但可以在断点后添加打印语句验证filename的值:
printf("当前要打开的文件:%s\n", filename);
重新编译调试,确认输出的文件名是否正确,同时检查reverse.txt是否存在、是否有读权限:
ls -l ./reverse.txt
4. 调整调试配置的启动断点
在launch.json的配置项中添加"stopAtEntry": true,让程序启动时直接停在main函数入口,再逐步调试,便于排查问题:
{ "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", "program": "${workspaceRoot}/utils/reverse", "cwd": "${workspaceRoot}/utils", "args": ["reverse.txt"], "stopAtEntry": true, // 新增该配置 "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true }, { "description": "Set Disassembly Flavor to Intel", "text": "-gdb-set disassembly-flavor intel", "ignoreFailures": true } ] }
内容的提问来源于stack exchange,提问作者Nicholas Humphrey
相关产品推荐
相关产品推荐

