189 lines
4.5 KiB
Markdown
189 lines
4.5 KiB
Markdown
|
|
# 段错误诊断指南
|
|||
|
|
|
|||
|
|
## 常见段错误原因
|
|||
|
|
|
|||
|
|
### 1. **空指针访问**
|
|||
|
|
```cpp
|
|||
|
|
// 危险:没有检查指针是否为空
|
|||
|
|
auto& input_channels = std::get<std::vector<std::vector<float>>>(data.channel_data);
|
|||
|
|
|
|||
|
|
// 安全:先检查variant状态
|
|||
|
|
if (data.channel_data.valueless_by_exception()) {
|
|||
|
|
throw std::runtime_error("Channel data is in invalid state");
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. **数组越界**
|
|||
|
|
```cpp
|
|||
|
|
// 危险:直接访问数组元素
|
|||
|
|
for (int i = 0; i < 8; ++i) {
|
|||
|
|
output_channels[i] = input_channels[i]; // 可能越界
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 安全:先检查数组大小
|
|||
|
|
if (input_channels.size() < 8) {
|
|||
|
|
throw std::runtime_error("Not enough channels");
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. **空容器访问**
|
|||
|
|
```cpp
|
|||
|
|
// 危险:访问空容器
|
|||
|
|
if (!input_channels.empty()) {
|
|||
|
|
auto min_val = *std::min_element(input_channels[0].begin(), input_channels[0].end());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 安全:检查容器是否为空
|
|||
|
|
if (!input_channels.empty() && !input_channels[0].empty()) {
|
|||
|
|
auto min_val = *std::min_element(input_channels[0].begin(), input_channels[0].end());
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 已修复的问题
|
|||
|
|
|
|||
|
|
### 1. **MAPPER函数增强安全检查**
|
|||
|
|
- 添加了`valueless_by_exception()`检查
|
|||
|
|
- 验证输入通道是否为空
|
|||
|
|
- 检查每个通道是否有数据
|
|||
|
|
- 提供详细的错误信息
|
|||
|
|
|
|||
|
|
### 2. **Main函数增强调试功能**
|
|||
|
|
- 添加了`debug_channel_data()`函数
|
|||
|
|
- 在每个处理阶段显示数据状态
|
|||
|
|
- 使用try-catch包装每个映射操作
|
|||
|
|
- 提供详细的处理进度信息
|
|||
|
|
|
|||
|
|
## 调试步骤
|
|||
|
|
|
|||
|
|
### 步骤1:运行测试模式1
|
|||
|
|
```
|
|||
|
|
请选择测试模式:
|
|||
|
|
1. 测试新解析函数 (查看解析结果)
|
|||
|
|
2. 运行原有测试流程
|
|||
|
|
请输入选择 (1 或 2): 1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**目的**: 验证解析器是否正常工作
|
|||
|
|
|
|||
|
|
### 步骤2:检查解析结果
|
|||
|
|
- 查看每个数据对象的详细信息
|
|||
|
|
- 确认通道数据格式正确
|
|||
|
|
- 验证采样点数合理
|
|||
|
|
|
|||
|
|
### 步骤3:运行测试模式2
|
|||
|
|
```
|
|||
|
|
请输入选择 (1 或 2): 2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**目的**: 逐步执行完整流程,定位问题
|
|||
|
|
|
|||
|
|
### 步骤4:观察调试输出
|
|||
|
|
```
|
|||
|
|
=== 调试信息: 解析后 ===
|
|||
|
|
数据类型: ECG_12LEAD (12导联心电)
|
|||
|
|
包序号: 0
|
|||
|
|
时间戳: 1234567890
|
|||
|
|
多通道数据: 8 个通道
|
|||
|
|
通道 0: 42 个采样点 [范围: -1.25 ~ 1.45]
|
|||
|
|
通道 1: 42 个采样点 [范围: -0.98 ~ 1.23]
|
|||
|
|
...
|
|||
|
|
原始数据大小: 1234 字节
|
|||
|
|
================================
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 常见问题排查
|
|||
|
|
|
|||
|
|
### 问题1:解析器返回空数据
|
|||
|
|
**症状**: 所有通道都是空的
|
|||
|
|
**可能原因**:
|
|||
|
|
- 文件路径错误
|
|||
|
|
- 文件格式不匹配
|
|||
|
|
- 解析逻辑错误
|
|||
|
|
|
|||
|
|
**解决方案**:
|
|||
|
|
```cpp
|
|||
|
|
// 检查文件是否存在
|
|||
|
|
if (file_content.empty()) {
|
|||
|
|
throw std::runtime_error("File is empty or cannot be read");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查文件大小
|
|||
|
|
std::cout << "文件大小: " << file_content.size() << " 字节" << std::endl;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 问题2:通道数量不匹配
|
|||
|
|
**症状**: 期望8个通道,但只有3个
|
|||
|
|
**可能原因**:
|
|||
|
|
- 设备类型识别错误
|
|||
|
|
- 数据包不完整
|
|||
|
|
- 解析逻辑有bug
|
|||
|
|
|
|||
|
|
**解决方案**:
|
|||
|
|
```cpp
|
|||
|
|
// 在MAPPER中添加详细检查
|
|||
|
|
if (input_channels.size() < expected_channels) {
|
|||
|
|
std::string error_msg = "Expected " + std::to_string(expected_channels) +
|
|||
|
|
" channels, but got " + std::to_string(input_channels.size());
|
|||
|
|
throw std::runtime_error(error_msg);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 问题3:通道数据为空
|
|||
|
|
**症状**: 通道存在但采样点数为0
|
|||
|
|
**可能原因**:
|
|||
|
|
- 数据包损坏
|
|||
|
|
- 解析偏移错误
|
|||
|
|
- 数据类型不匹配
|
|||
|
|
|
|||
|
|
**解决方案**:
|
|||
|
|
```cpp
|
|||
|
|
// 检查每个通道的数据
|
|||
|
|
for (size_t i = 0; i < input_channels.size(); ++i) {
|
|||
|
|
if (input_channels[i].empty()) {
|
|||
|
|
throw std::runtime_error("Channel " + std::to_string(i) + " is empty");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 预防措施
|
|||
|
|
|
|||
|
|
### 1. **始终检查variant状态**
|
|||
|
|
```cpp
|
|||
|
|
if (data.channel_data.valueless_by_exception()) {
|
|||
|
|
throw std::runtime_error("Invalid variant state");
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. **验证容器大小**
|
|||
|
|
```cpp
|
|||
|
|
if (container.empty()) {
|
|||
|
|
throw std::runtime_error("Container is empty");
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. **边界检查**
|
|||
|
|
```cpp
|
|||
|
|
if (index >= container.size()) {
|
|||
|
|
throw std::runtime_error("Index out of bounds");
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. **类型安全访问**
|
|||
|
|
```cpp
|
|||
|
|
if (!std::holds_alternative<ExpectedType>(data.channel_data)) {
|
|||
|
|
throw std::runtime_error("Unexpected data type");
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 运行建议
|
|||
|
|
|
|||
|
|
1. **先运行模式1**: 确保解析器工作正常
|
|||
|
|
2. **观察调试输出**: 检查每个阶段的数据状态
|
|||
|
|
3. **逐步排查**: 如果出错,查看具体是哪个数据对象或通道
|
|||
|
|
4. **检查文件**: 确认数据文件完整且格式正确
|
|||
|
|
|
|||
|
|
如果仍然出现段错误,请提供:
|
|||
|
|
- 完整的错误信息
|
|||
|
|
- 调试输出内容
|
|||
|
|
- 数据文件的基本信息(大小、格式等)
|