如何发现 Arduino C 代码中的内存溢出错误?

电器工程 Arduino 编译器 调试
2022-02-04 02:07:06

有几次,在将代码上传到 Arduino 后,串行监视器上出现了一些可疑的输出:比如空格的永久输出或突然切断的字符串或加扰的字符串。

因为在 Arduino IDE 中没有编译错误或警告,所以我认为 Arduino 坏了,但经过一些测试后,我发现 Arduino IDE 编译器并没有捕捉到所有类型的错误——尤其是在为数组结构分配循环中的变量时。这似乎在短时间内使 Arduino 崩溃。

如何发现 Arduino IDE 未显示的错误?

3个回答

MemoryFree可以帮助您发现内存使用的风险。

例子:

#include <MemoryFree.h>

// On Arduino Duemilanove with ATmega328:
//
// Reported free memory with str commented out:
// 1824 bytes
//
// Reported free memory with str and Serial.println(str) uncommented:
// 1810
//
// Difference: 14 bytes (13 ascii chars + null terminator)

// 14-bytes string
//char str[] = "Hello, world!";


void setup() {
    Serial.begin(115200);
}


void loop() {
    //Serial.println(str);

    Serial.print("freeMemory()=");
    Serial.println(freeMemory());

    delay(1000);
}

我不确定 MemoryFree 是否考虑了堆栈指针。如果您的堆栈指针与您的堆指针冲突,您可能会遇到分段错误。

RAM 耗尽的最常见原因是使用 String 对象或使用大量常量字符数组(c 样式字符串)。

Forutantly IDE 1.0.4 包含对 malloc 的修复,该修复困扰了字符串对象很长时间。

减少常量字符串浪费的 RAM,例如:

Serial.print("Hello World");  // This consumes RAM!

您可以使用 F() 宏。此宏将强制字符数组留在 PROGMEM 中。使用数组时,只消耗一个字节的内存。

Serial.print(F("Hello World"));  // Keeps the character-array in PROGMEM

请记住,存储在 PROGMEM 中的字符串在运行时不能更改。

就发现而言,没有调试器或内存控制器,您必须使用老式的检测技术来查找问题发生的位置。

看起来您在这里谈论的是运行时错误(内存泄漏/段错误类型)。

没有任何方法可以在已经编写的代码中发现此类错误(除非您非常仔细地梳理代码)。但是,在编写代码时很容易防止这些情况发生。在编写循环或递归调用时要非常小心;问问自己“这会失控吗?”。如果看起来这些是它“失控”的范围,那么编写代码来防止这种情况发生。

关于段错误——只需检查数组索引的边界值就可以了。如果您使用的是指针,那么请注意指针运算。