【Linux C/C++开发】第6章:错误处理与调试
·
第5章:错误处理与调试
🎯 学习目标
- 掌握错误处理机制
- 学会使用调试工具
- 理解异常处理(C++)
- 掌握基本的调试技巧
- 了解代码规范和最佳实践
📅 学习时间安排
- 总时长: 15-20小时
- 理论学习: 6小时
- 编程实践: 12小时
- 代码量目标: 300行
第一章:错误处理基础
1.1 错误处理的重要性
在编程中,错误处理是确保程序稳定性和可靠性的关键。良好的错误处理可以:
- 防止程序崩溃
- 提供有用的错误信息
- 帮助快速定位和修复问题
- 提高用户体验
1.2 C语言错误处理机制
1.2.1 返回值检查
C语言主要通过函数返回值来指示错误状态:
#include <stdio.h>
#include <stdlib.h>
// 示例:文件操作错误处理
int read_file(const char* filename) {
FILE* file = fopen(filename, "r");
if (file == NULL) {
printf("错误:无法打开文件 %s\n", filename);
return -1; // 返回错误码
}
// 读取文件内容...
fclose(file);
return 0; // 成功返回0
}
// 示例:内存分配错误处理
int* create_array(int size) {
int* array = (int*)malloc(size * sizeof(int));
if (array == NULL) {
printf("错误:内存分配失败\n");
return NULL; // 返回NULL表示错误
}
return array;
}
1.2.2 errno机制
C标准库提供了全局变量errno来指示错误类型:
#include <stdio.h>
#include <errno.h>
#include <string.h>
void demonstrate_errno() {
FILE* file = fopen("nonexistent.txt", "r");
if (file == NULL) {
printf("错误号: %d\n", errno);
printf("错误信息: %s\n", strerror(errno));
perror("perror输出"); // 自动添加错误信息
}
}
// 自定义错误处理函数
void handle_error(const char* operation) {
fprintf(stderr, "%s 失败: %s (错误号: %d)\n",
operation, strerror(errno), errno);
}
1.2.3 错误码定义
定义清晰的错误码有助于错误处理:
// 自定义错误码
typedef enum {
SUCCESS = 0,
ERROR_FILE_NOT_FOUND = -1,
ERROR_PERMISSION_DENIED = -2,
ERROR_OUT_OF_MEMORY = -3,
ERROR_INVALID_PARAM = -4,
ERROR_NETWORK_TIMEOUT = -5
} ErrorCode;
// 错误码转换函数
const char* error_to_string(ErrorCode code) {
switch (code) {
case SUCCESS: return "成功";
case ERROR_FILE_NOT_FOUND: return "文件未找到";
case ERROR_PERMISSION_DENIED: return "权限被拒绝";
case ERROR_OUT_OF_MEMORY: return "内存不足";
case ERROR_INVALID_PARAM: return "参数无效";
case ERROR_NETWORK_TIMEOUT: return "网络超时";
default: return "未知错误";
}
}
1.3 C++异常处理机制
1.3.1 基本语法
C++提供了更强大的异常处理机制:
#include <iostream>
#include <stdexcept>
#include <string>
void demonstrate_basic_exceptions() {
try {
int divisor = 0;
if (divisor == 0) {
throw std::runtime_error("除数不能为零");
}
int result = 10 / divisor;
std::cout << "结果: " << result << std::endl;
}
catch (const std::exception& e) {
std::cerr << "捕获异常: " << e.what() << std::endl;
}
}
1.3.2 异常类型层次
标准异常类的层次结构:
#include <exception>
#include <stdexcept>
#include <new>
#include <typeinfo>
void demonstrate_exception_hierarchy() {
try {
// 可能抛出不同类型的异常
int choice;
std::cout << "选择异常类型 (1-5): ";
std::cin >> choice;
switch (choice) {
case 1:
throw std::runtime_error("运行时错误");
case 2:
throw std::logic_error("逻辑错误");
case 3:
throw std::out_of_range("超出范围");
case 4:
throw std::bad_alloc(); // 内存分配失败
case 5:
throw std::invalid_argument("无效参数");
}
}
catch (const std::bad_alloc& e) {
std::cerr << "内存分配异常: " << e.what() << std::endl;
}
catch (const std::out_of_range& e) {
std::cerr << "范围异常: " << e.what() << std::endl;
}
catch (const std::invalid_argument& e) {
std::cerr << "参数异常: " << e.what() << std::endl;
}
catch (const std::exception& e) {
std::cerr << "标准异常: " << e.what() << std::endl;
}
catch (...) {
std::cerr << "未知异常" << std::endl;
}
}
1.3.3 自定义异常类
创建自定义异常类:
#include <string>
#include <exception>
// 自定义异常类
class FileException : public std::exception {
private:
std::string message;
std::string filename;
public:
FileException(const std::string& msg, const std::string& file)
: message(msg), filename(file) {}
const char* what() const noexcept override {
return ("文件错误: " + message + " (" + filename + ")").c_str();
}
const std::string& get_filename() const { return filename; }
};
class NetworkException : public std::exception {
private:
std::string message;
int error_code;
public:
NetworkException(const std::string& msg, int code)
: message(msg), error_code(code) {}
const char* what() const noexcept override {
return ("网络错误: " + message).c_str();
}
int get_error_code() const { return error_code; }
};
1.4 日志记录系统
1.4.1 简单日志系统
实现基本的日志记录功能:
#include <stdio.h>
#include <time.h>
#include <stdarg.h>
typedef enum {
LOG_DEBUG,
LOG_INFO,
LOG_WARNING,
LOG_ERROR,
LOG_FATAL
} LogLevel;
// 日志级别名称
const char* log_level_names[] = {
"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"
};
// 日志函数
void write_log(LogLevel level, const char* format, ...) {
FILE* log_file = fopen("application.log", "a");
if (log_file == NULL) return;
// 获取当前时间
time_t now = time(NULL);
struct tm* time_info = localtime(&now);
char time_str[20];
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", time_info);
// 输出时间戳和日志级别
fprintf(log_file, "[%s] [%s] ", time_str, log_level_names[level]);
// 输出日志内容
va_list args;
va_start(args, format);
vfprintf(log_file, format, args);
va_end(args);
fprintf(log_file, "\n");
fclose(log_file);
// 如果是致命错误,同时输出到控制台
if (level >= LOG_ERROR) {
printf("[%s] [%s] ", time_str, log_level_names[level]);
va_list console_args;
va_start(console_args, format);
vprintf(format, console_args);
va_end(console_args);
printf("\n");
}
}
1.4.2 C++日志类
使用面向对象方式实现日志系统:
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <mutex>
enum class LogLevel {
DEBUG,
INFO,
WARNING,
ERROR,
FATAL
};
class Logger {
private:
std::ofstream log_file;
std::mutex log_mutex;
static Logger* instance;
Logger(const std::string& filename) {
log_file.open(filename, std::ios::app);
}
public:
~Logger() {
if (log_file.is_open()) {
log_file.close();
}
}
// 单例模式
static Logger* get_instance(const std::string& filename = "app.log") {
if (instance == nullptr) {
instance = new Logger(filename);
}
return instance;
}
void log(LogLevel level, const std::string& message) {
std::lock_guard<std::mutex> lock(log_mutex);
// 获取当前时间
auto now = std::time(nullptr);
auto time_info = std::localtime(&now);
char time_buffer[20];
std::strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", time_info);
// 日志级别字符串
const char* level_str[] = {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
// 写入日志文件
log_file << "[" << time_buffer << "] [" << level_str[static_cast<int>(level)] << "] "
<< message << std::endl;
// 错误级别以上同时输出到控制台
if (level >= LogLevel::ERROR) {
std::cerr << "[" << time_buffer << "] [" << level_str[static_cast<int>(level)] << "] "
<< message << std::endl;
}
}
void debug(const std::string& msg) { log(LogLevel::DEBUG, msg); }
void info(const std::string& msg) { log(LogLevel::INFO, msg); }
void warning(const std::string& msg) { log(LogLevel::WARNING, msg); }
void error(const std::string& msg) { log(LogLevel::ERROR, msg); }
void fatal(const std::string& msg) { log(LogLevel::FATAL, msg); }
};
// 静态成员定义
Logger* Logger::instance = nullptr;
第二章:调试技巧与工具
2.1 基本调试概念
2.1.1 调试的重要性
调试是程序开发中不可或缺的技能:
- 快速定位和修复bug
- 理解程序执行流程
- 验证程序逻辑正确性
- 性能分析和优化
2.1.2 常见错误类型
// 1. 语法错误(编译时捕获)
int main() {
int x = 10 // 缺少分号
return 0;
}
// 2. 运行时错误
void runtime_errors() {
int arr[5] = {1, 2, 3, 4, 5};
// 数组越界
int value = arr[10]; // 运行时错误
// 空指针解引用
int* ptr = nullptr;
*ptr = 100; // 段错误
// 内存泄漏
int* leak = new int[1000];
// 忘记delete[]
}
// 3. 逻辑错误
int divide(int a, int b) {
// 逻辑错误:应该是 b != 0
if (b == 0) {
return a / b; // 仍然会执行除法
}
return a / b;
}
2.2 使用GDB调试器
2.2.1 GDB基础命令
# 编译时添加调试信息
g++ -g -o program program.cpp
# 启动GDB
gdb program
# GDB常用命令
(gdb) run # 运行程序
(gdb) break main # 设置断点
(gdb) break 25 # 在第25行设置断点
(gdb) next # 单步执行(不进入函数)
(gdb) step # 单步执行(进入函数)
(gdb) continue # 继续执行
(gdb) print variable # 打印变量值
(gdb) display variable # 持续显示变量
(gdb) info breakpoints # 查看断点信息
(gdb) delete 1 # 删除断点1
(gdb) backtrace # 查看调用栈
(gdb) quit # 退出GDB
2.2.2 GDB调试示例
// debug_example.cpp
#include <iostream>
#include <vector>
class Calculator {
public:
int divide(int a, int b) {
if (b == 0) {
throw std::runtime_error("除数不能为零");
}
return a / b;
}
int factorial(int n) {
if (n < 0) return 0;
if (n == 0) return 1;
return n * factorial(n - 1);
}
};
int main() {
Calculator calc;
try {
int result = calc.divide(10, 2);
std::cout << "10 / 2 = " << result << std::endl;
result = calc.divide(10, 0); // 这里会抛出异常
std::cout << "10 / 0 = " << result << std::endl;
}
catch (const std::exception& e) {
std::cerr << "错误: " << e.what() << std::endl;
}
int fact = calc.factorial(5);
std::cout << "5! = " << fact << std::endl;
return 0;
}
GDB调试会话:
$ g++ -g -o debug_example debug_example.cpp
$ gdb debug_example
(gdb) break main
(gdb) run
(gdb) next
(gdb) step
(gdb) print result
(gdb) display result
(gdb) continue
2.3 内存调试
2.3.1 Valgrind内存检测
# 安装valgrind
sudo apt-get install valgrind
# 使用valgrind检测内存泄漏
valgrind --leak-check=full ./program
# 检测内存错误
valgrind --tool=memcheck ./program
2.3.2 内存调试示例
// memory_debug.cpp
#include <iostream>
void memory_errors() {
// 1. 内存泄漏
int* leak = new int[100];
// 忘记delete[]
// 2. 数组越界
int* arr = new int[10];
arr[10] = 100; // 越界访问
// 3. 重复释放
int* dup = new int;
delete dup;
delete dup; // 重复释放
// 4. 使用已释放的内存
int* used = new int;
delete used;
*used = 200; // 使用已释放的内存
delete[] arr;
}
int main() {
memory_errors();
return 0;
}
Valgrind输出分析:
$ g++ -g -o memory_debug memory_debug.cpp
$ valgrind --leak-check=full ./memory_debug
2.4 调试宏和断言
2.4.1 调试宏定义
#include <stdio.h>
#include <assert.h>
// 调试宏定义
#ifdef DEBUG
#define DEBUG_PRINT(fmt, ...) printf("DEBUG: " fmt "\n", ##__VA_ARGS__)
#define DEBUG_VAR(var) printf("DEBUG: %s = %d\n", #var, var)
#define FUNCTION_ENTER() printf("进入函数: %s\n", __FUNCTION__)
#define FUNCTION_EXIT() printf("退出函数: %s\n", __FUNCTION__)
#else
#define DEBUG_PRINT(fmt, ...)
#define DEBUG_VAR(var)
#define FUNCTION_ENTER()
#define FUNCTION_EXIT()
#endif
// 使用示例
void test_function(int x) {
FUNCTION_ENTER();
DEBUG_PRINT("参数 x = %d", x);
int result = x * 2;
DEBUG_VAR(result);
FUNCTION_EXIT();
}
2.4.2 断言使用
#include <cassert>
#include <iostream>
class Array {
private:
int* data;
int size;
public:
Array(int s) : size(s) {
assert(s > 0); // 确保数组大小为正数
data = new int[size];
}
int& operator[](int index) {
// 使用断言检查数组越界(调试模式下)
assert(index >= 0 && index < size);
return data[index];
}
int get_size() const { return size; }
~Array() {
delete[] data;
}
};
// 运行时检查(发布版本也有效)
void safe_array_access(Array& arr, int index) {
if (index < 0 || index >= arr.get_size()) {
std::cerr << "错误:数组越界访问,索引 " << index
<< ",数组大小 " << arr.get_size() << std::endl;
return;
}
std::cout << "arr[" << index << "] = " << arr[index] << std::endl;
}
2.5 性能分析和优化
2.5.1 代码性能分析
#include <chrono>
#include <iostream>
#include <vector>
#include <algorithm>
class PerformanceTimer {
private:
std::chrono::high_resolution_clock::time_point start_time;
std::string operation_name;
public:
PerformanceTimer(const std::string& name)
: operation_name(name), start_time(std::chrono::high_resolution_clock::now()) {}
~PerformanceTimer() {
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
std::cout << operation_name << " 耗时: " << duration.count() << " 微秒" << std::endl;
}
};
// 性能测试示例
void performance_test() {
const int SIZE = 100000;
std::vector<int> data(SIZE);
// 生成随机数据
std::generate(data.begin(), data.end(), rand);
{
PerformanceTimer timer("冒泡排序");
// 复制数据进行排序测试
std::vector<int> bubble_data = data;
// 简单的冒泡排序实现
for (int i = 0; i < bubble_data.size() - 1; i++) {
for (int j = 0; j < bubble_data.size() - i - 1; j++) {
if (bubble_data[j] > bubble_data[j + 1]) {
std::swap(bubble_data[j], bubble_data[j + 1]);
}
}
}
}
{
PerformanceTimer timer("STL排序");
std::vector<int> stl_data = data;
std::sort(stl_data.begin(), stl_data.end());
}
}
第三章:代码规范与最佳实践
3.1 命名规范
3.1.1 命名约定
// 良好的命名示例
class StudentRecordManager {
private:
int total_students;
std::vector<Student> student_list;
public:
void addStudent(const Student& new_student);
Student* findStudentById(int student_id);
double calculateAverageGrade() const;
private:
bool validateStudentData(const Student& student) const;
};
// 使用命名空间避免冲突
namespace university {
namespace records {
class StudentManager {
// ...
};
}
}
// 常量命名
const int MAX_STUDENTS_PER_CLASS = 30;
const double PI_VALUE = 3.14159265359;
// 枚举命名
enum class StudentStatus {
ACTIVE,
INACTIVE,
GRADUATED,
SUSPENDED
};
3.2 代码组织
3.2.1 头文件结构
// student.h - 头文件
#ifndef STUDENT_H
#define STUDENT_H
#include <string>
#include <vector>
namespace university {
namespace records {
class Student {
private:
int id;
std::string name;
int age;
std::vector<double> grades;
public:
// 构造函数
Student(int student_id, const std::string& student_name, int student_age);
// getter方法
int getId() const { return id; }
const std::string& getName() const { return name; }
int getAge() const { return age; }
// 成绩管理
void addGrade(double grade);
double getAverageGrade() const;
// 验证函数
bool isValid() const;
private:
// 私有辅助函数
bool validateGrade(double grade) const;
};
} // namespace records
} // namespace university
#endif // STUDENT_H
3.2.2 源文件实现
// student.cpp - 实现文件
#include "student.h"
#include <stdexcept>
#include <numeric>
#include <algorithm>
namespace university {
namespace records {
Student::Student(int student_id, const std::string& student_name, int student_age)
: id(student_id), name(student_name), age(student_age) {
if (!isValid()) {
throw std::invalid_argument("Invalid student data");
}
}
void Student::addGrade(double grade) {
if (!validateGrade(grade)) {
throw std::out_of_range("Grade must be between 0 and 100");
}
grades.push_back(grade);
}
double Student::getAverageGrade() const {
if (grades.empty()) {
return 0.0;
}
double sum = std::accumulate(grades.begin(), grades.end(), 0.0);
return sum / grades.size();
}
bool Student::isValid() const {
return id > 0 && !name.empty() && age > 0 && age < 150;
}
bool Student::validateGrade(double grade) const {
return grade >= 0.0 && grade <= 100.0;
}
} // namespace records
} // namespace university
3.3 错误处理最佳实践
3.3.1 防御式编程
#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>
class FileProcessor {
private:
std::string filename;
std::ifstream file;
public:
FileProcessor(const std::string& fname) : filename(fname) {
validateFilename();
}
~FileProcessor() {
if (file.is_open()) {
file.close();
}
}
void openFile() {
file.open(filename);
if (!file.is_open()) {
throw std::runtime_error("无法打开文件: " + filename);
}
// 检查文件是否为空
if (file.peek() == std::ifstream::traits_type::eof()) {
throw std::runtime_error("文件为空: " + filename);
}
}
std::string readLine() {
if (!file.is_open()) {
throw std::logic_error("文件未打开");
}
std::string line;
if (!std::getline(file, line)) {
if (file.eof()) {
throw std::runtime_error("到达文件末尾");
} else {
throw std::runtime_error("读取文件时发生错误");
}
}
return line;
}
bool hasMoreLines() const {
return file.is_open() && !file.eof();
}
private:
void validateFilename() {
if (filename.empty()) {
throw std::invalid_argument("文件名不能为空");
}
if (filename.length() > 255) {
throw std::invalid_argument("文件名过长");
}
// 检查文件名是否包含非法字符
const std::string invalid_chars = "\\/:*?\"<>|";
if (filename.find_first_of(invalid_chars) != std::string::npos) {
throw std::invalid_argument("文件名包含非法字符");
}
}
};
// 使用示例
defensive_programming_example() {
try {
FileProcessor processor("data.txt");
processor.openFile();
while (processor.hasMoreLines()) {
std::string line = processor.readLine();
std::cout << "读取行: " << line << std::endl;
}
std::cout << "文件处理完成" << std::endl;
}
catch (const std::invalid_argument& e) {
std::cerr << "参数错误: " << e.what() << std::endl;
}
catch (const std::runtime_error& e) {
std::cerr << "运行时错误: " << e.what() << std::endl;
}
catch (const std::exception& e) {
std::cerr << "未知错误: " << e.what() << std::endl;
}
}
3.4 版本控制基础
3.4.1 Git基础操作
# 初始化Git仓库
git init
# 添加文件到暂存区
git add filename.cpp
git add . # 添加所有文件
# 提交更改
git commit -m "添加错误处理功能"
# 查看状态
git status
# 查看提交历史
git log --oneline
# 创建分支
git branch feature-error-handling
git checkout feature-error-handling
# 合并分支
git checkout main
git merge feature-error-handling
# 推送到远程仓库
git remote add origin https://github.com/username/repo.git
git push -u origin main
综合练习项目
项目:带错误处理的计算器
// error_handling_calculator.cpp
#include <iostream>
#include <string>
#include <stdexcept>
#include <cmath>
#include <limits>
class CalculatorError : public std::runtime_error {
public:
CalculatorError(const std::string& message)
: std::runtime_error("计算器错误: " + message) {}
};
class Calculator {
private:
double last_result;
int operation_count;
public:
Calculator() : last_result(0.0), operation_count(0) {}
double add(double a, double b) {
validateInput(a);
validateInput(b);
last_result = a + b;
operation_count++;
return last_result;
}
double subtract(double a, double b) {
validateInput(a);
validateInput(b);
last_result = a - b;
operation_count++;
return last_result;
}
double multiply(double a, double b) {
validateInput(a);
validateInput(b);
last_result = a * b;
operation_count++;
return last_result;
}
double divide(double a, double b) {
validateInput(a);
validateInput(b);
if (std::abs(b) < std::numeric_limits<double>::epsilon()) {
throw CalculatorError("除数不能为零");
}
last_result = a / b;
operation_count++;
return last_result;
}
double power(double base, double exponent) {
validateInput(base);
validateInput(exponent);
if (base == 0.0 && exponent < 0.0) {
throw CalculatorError("0的负数次幂无定义");
}
last_result = std::pow(base, exponent);
operation_count++;
return last_result;
}
double square_root(double value) {
validateInput(value);
if (value < 0.0) {
throw CalculatorError("负数没有实数平方根");
}
last_result = std::sqrt(value);
operation_count++;
return last_result;
}
double getLastResult() const {
return last_result;
}
int getOperationCount() const {
return operation_count;
}
void reset() {
last_result = 0.0;
operation_count = 0;
}
private:
void validateInput(double value) {
if (!std::isfinite(value)) {
throw CalculatorError("输入值必须是有限数");
}
if (std::abs(value) > 1e308) {
throw CalculatorError("输入值过大");
}
}
};
// 用户界面类
class CalculatorUI {
private:
Calculator calc;
public:
void run() {
std::cout << "=== 高级计算器 ===" << std::endl;
std::cout << "支持操作: +, -, *, /, ^(幂), sqrt(平方根), clear, history, quit" << std::endl;
while (true) {
try {
std::string command;
std::cout << "\n输入命令: ";
std::cin >> command;
if (command == "quit") {
std::cout << "感谢使用计算器!" << std::endl;
break;
}
else if (command == "clear") {
calc.reset();
std::cout << "计算器已重置" << std::endl;
}
else if (command == "history") {
showHistory();
}
else if (command == "+") {
performBinaryOperation(&Calculator::add, "加法");
}
else if (command == "-") {
performBinaryOperation(&Calculator::subtract, "减法");
}
else if (command == "*") {
performBinaryOperation(&Calculator::multiply, "乘法");
}
else if (command == "/") {
performBinaryOperation(&Calculator::divide, "除法");
}
else if (command == "^") {
performBinaryOperation(&Calculator::power, "幂运算");
}
else if (command == "sqrt") {
performUnaryOperation(&Calculator::square_root, "平方根");
}
else {
std::cout << "未知命令: " << command << std::endl;
showHelp();
}
}
catch (const CalculatorError& e) {
std::cerr << "错误: " << e.what() << std::endl;
std::cerr << "请检查输入并重试" << std::endl;
}
catch (const std::exception& e) {
std::cerr << "系统错误: " << e.what() << std::endl;
}
}
}
private:
void showHelp() {
std::cout << "可用命令:" << std::endl;
std::cout << " + : 加法运算" << std::endl;
std::cout << " - : 减法运算" << std::endl;
std::cout << " * : 乘法运算" << std::endl;
std::cout << " / : 除法运算" << std::endl;
std::cout << " ^ : 幂运算" << std::endl;
std::cout << " sqrt : 平方根" << std::endl;
std::cout << " clear : 重置计算器" << std::endl;
std::cout << " history : 显示历史记录" << std::endl;
std::cout << " quit : 退出程序" << std::endl;
}
void showHistory() {
std::cout << "操作次数: " << calc.getOperationCount() << std::endl;
std::cout << "上次结果: " << calc.getLastResult() << std::endl;
}
void performBinaryOperation(double (Calculator::*op)(double, double), const std::string& op_name) {
double a, b;
std::cout << "输入两个数字: ";
std::cin >> a >> b;
double result = (calc.*op)(a, b);
std::cout << "结果: " << result << std::endl;
}
void performUnaryOperation(double (Calculator::*op)(double), const std::string& op_name) {
double value;
std::cout << "输入数字: ";
std::cin >> value;
double result = (calc.*op)(value);
std::cout << "结果: " << result << std::endl;
}
};
int main() {
try {
CalculatorUI ui;
ui.run();
}
catch (const std::exception& e) {
std::cerr << "程序运行失败: " << e.what() << std::endl;
return 1;
}
return 0;
}
学习评估
理论知识检查
-
错误处理机制
- 理解C语言的errno机制
- 掌握C++异常处理语法
- 了解自定义异常类的创建
- 理解日志记录的重要性
-
调试技能
- 会使用GDB基本命令
- 能够设置断点和单步执行
- 掌握内存调试工具的使用
- 了解性能分析方法
-
代码质量
- 遵循命名规范
- 编写防御式代码
- 使用版本控制系统
- 编写清晰的注释
编程练习
-
基础练习
- 编写带错误检查的文件复制程序
- 实现简单的日志系统
- 创建自定义异常类
-
进阶练习
- 使用GDB调试复杂程序
- 实现内存泄漏检测
- 编写性能测试工具
-
综合项目
- 完成带错误处理的计算器
- 添加完整的日志记录
- 编写单元测试
代码量统计
- 错误处理示例代码:150行
- 调试工具示例:100行
- 计算器项目:200行
- 总计:450行(超出目标150行)
学习建议
调试技巧
-
系统性调试
- 从错误信息开始分析
- 逐步缩小问题范围
- 使用二分法定位bug
-
日志策略
- 记录关键操作
- 包含时间戳
- 分级记录(DEBUG/INFO/ERROR)
-
测试驱动
- 先写测试用例
- 逐步完善功能
- 持续集成测试
常见陷阱
-
忽略错误检查
- 总是检查返回值
- 处理异常情况
- 提供有用的错误信息
-
过度使用异常
- 异常用于异常情况
- 不要用于正常控制流
- 保持异常处理简洁
-
调试信息泄露
- 发布版本移除调试信息
- 不要在生产环境中暴露详细错误
- 记录安全相关的错误
下一章:第六周:综合复习与项目
返回目录:基础阶段学习计划
更多推荐


所有评论(0)