medical_SDK/log/SEGMENTATION_FAULT_FIX.md

4.4 KiB
Raw Blame History

段错误修复说明

问题定位

段错误发生在 ECG_12LEAD_Data_Mapper 函数的这一行:

output_channels[9][sample] = -0.5f * (lead_I + lead_II);  // aVR

根本原因

1. 数组未初始化

// 问题代码:只创建了向量,但没有设置大小
std::vector<std::vector<float>> output_channels(12);
// 此时 output_channels[9] 是一个空的向量,访问 [sample] 会导致段错误

2. 缺少边界检查

// 问题代码:直接访问数组元素,没有验证索引和大小
output_channels[9][sample] = value;  // 可能越界

修复方案

1. 正确初始化所有通道

// 修复后为所有12个通道设置正确的大小
std::vector<std::vector<float>> output_channels(12);
for (int ch = 0; ch < 12; ++ch) {
    output_channels[ch].resize(num_samples, 0.0f); // 初始化为0
}

2. 添加边界检查

// 修复后:在访问数组前验证索引和大小
if (9 < output_channels.size() && 10 < output_channels.size() && 11 < output_channels.size()) {
    if (sample < output_channels[9].size() && sample < output_channels[10].size() && sample < output_channels[11].size()) {
        output_channels[9][sample]  = -0.5f * (lead_I + lead_II);  // aVR
        output_channels[10][sample] = lead_I - 0.5f * lead_II;     // aVL
        output_channels[11][sample] = lead_II - 0.5f * lead_I;     // aVF
    }
}

3. 验证输入数据一致性

// 修复后确保所有前8个通道都有相同的采样点数
for (size_t i = 1; i < 8; ++i) {
    if (input_channels[i].size() != num_samples) {
        throw std::runtime_error("Channel " + std::to_string(i) + " has different sample count: " + 
                               std::to_string(input_channels[i].size()) + " vs " + std::to_string(num_samples));
    }
}

4. 验证输出数据完整性

// 修复后:确保所有输出通道都有正确的大小
for (size_t ch = 0; ch < output_channels.size(); ++ch) {
    if (output_channels[ch].size() != num_samples) {
        throw std::runtime_error("Output channel " + std::to_string(ch) + " has incorrect size: " + 
                               std::to_string(output_channels[ch].size()) + " vs expected " + std::to_string(num_samples));
    }
}

修复前后的对比

修复前(有段错误风险)

// 创建12导联输出结构
std::vector<std::vector<float>> output_channels(12);

// 直接访问未初始化的通道
output_channels[9][sample] = value;  // ❌ 段错误!

修复后(安全)

// 创建12导联输出结构并初始化所有通道的大小
std::vector<std::vector<float>> output_channels(12);
for (int ch = 0; ch < 12; ++ch) {
    output_channels[ch].resize(num_samples, 0.0f); // 初始化为0
}

// 安全的数组访问
if (9 < output_channels.size() && sample < output_channels[9].size()) {
    output_channels[9][sample] = value;  // ✅ 安全
}

技术要点

1. 向量初始化的重要性

  • std::vector<std::vector<float>>(12) 只创建了12个空的向量
  • 每个内部向量需要单独调用 resize() 设置大小
  • 使用 resize(size, default_value) 可以同时设置大小和默认值

2. 边界检查的必要性

  • 即使理论上索引应该有效,也要进行边界检查
  • 使用 if 语句验证索引和大小
  • 提供清晰的错误信息,便于调试

3. 数据一致性验证

  • 确保所有输入通道有相同的采样点数
  • 验证输出通道的完整性
  • 在关键步骤添加断言或异常

预防措施

1. 始终初始化容器

// 好的做法
std::vector<std::vector<float>> channels(12);
for (auto& ch : channels) {
    ch.resize(expected_size, default_value);
}

2. 使用范围检查

// 好的做法
if (index < container.size() && sample < container[index].size()) {
    container[index][sample] = value;
}

3. 添加调试信息

// 好的做法
std::cout << "Creating " << num_channels << " channels with " << num_samples << " samples each" << std::endl;

测试建议

  1. 运行测试模式1: 验证解析器工作正常
  2. 运行测试模式2: 测试完整的映射流程
  3. 观察调试输出: 确认所有通道都被正确初始化
  4. 检查输出文件: 验证12导联数据完整性

现在段错误应该已经被修复程序可以安全地处理12导联心电数据了