Arduino 内存类型,学术
Arduino memory types, academic
尊敬的 Whosebug 用户,
我有一个有趣的问题,我想听听你的意见,也请随时指正。
在普通 PC 中,内存地址分为 3 个部分,堆栈、堆、全局(现在让我们忘记外围设备),所以如果我继续做一个糟糕的递归函数,用调用填充堆栈,OS 将发送一条 Whosebug 消息,如果我在其中使用新关键字进行无限循环,它会用垃圾数据填充堆,并得到类似段错误的信息,但是如果我在arduino 项目?
try / catch 块不可用,所以我尝试在 loop() 中实现自己的错误处理,滥用预处理器的愚蠢:
#define THROW(errval) \
ERROR = errval; \
loop()
#define TRY \
if(ERROR == 0)
#define CATCH(err) \
else if(err == ERROR)
#define FINALLY \
if(ERROR != 0)
#define OUT_OF_MEMORY 1
int ERROR = 0;
void random_routine() {
if(/*something goes wrong*/) {
THROW(OUT_OF_MEMORY);
}
}
void start() { Serial.begin(9600); }
void loop() {
TRY {
random_routine();
} CATCH(OUT_OF_MEMORY) {
Serial.println("out of memory");
} FINALLY {
while(true);
}
}
现在你可能不会立即看到这里的技巧,所以这是你在预处理后得到的:
void random_routine() {
if(/*something goes wrong*/) {
ERROR = 1;
//this call is the body of my exception handling solution
//and the question is about this as well
loop();
}
}
void start() { Serial.begin(9600); }
void loop() {
///TRY-s macro result
if(ERROR == 0) {
random_routine();
///chainable CATCH blocks
} else if(ERROR == 1) {
Serial.println("Out of memory");
}
///FINALLY block
if(ERROR != 0) {
while(true);
}
}
所以我的问题是,如果由于某种原因内存满了,函数调用是否能够执行?因为 THROW 宏将始终以这种方式调用 loop(),我的想法是从当前上下文 'escape' 进入无限循环
抱歉我的英语不好
所以,如果你想退出一个函数,回到原来的地方,你应该离开这个函数,而不是调用原来的函数!通过从函数返回,或使用 setjmp
和 longjmp
.
而且在所有情况下,您还需要担心 "how does data get cleaned up"。换句话说,如果你分配了内存,那么你需要在离开函数之前释放它,或者你已经打开了一个文件,你需要关闭它等等。
这些事情正是 RAII 原则派上用场的地方,但它假设您将函数留在编译器的知识范围内,而不是您只是跳回主循环而不进行清理。迟早会出问题。
另请注意,堆栈溢出的行为是未定义的行为 - 它可能会立即使程序崩溃,或者可能导致堆被覆盖,格式化您的 harddrive/SD 卡,或者可能导致守护进程运行从你的鼻子里出来。或者你能想到的任何其他东西,然后是一些。它是未定义的,你不能依赖它做任何特别的事情——只是 "you're not supposed to do that".
尊敬的 Whosebug 用户,
我有一个有趣的问题,我想听听你的意见,也请随时指正。
在普通 PC 中,内存地址分为 3 个部分,堆栈、堆、全局(现在让我们忘记外围设备),所以如果我继续做一个糟糕的递归函数,用调用填充堆栈,OS 将发送一条 Whosebug 消息,如果我在其中使用新关键字进行无限循环,它会用垃圾数据填充堆,并得到类似段错误的信息,但是如果我在arduino 项目?
try / catch 块不可用,所以我尝试在 loop() 中实现自己的错误处理,滥用预处理器的愚蠢:
#define THROW(errval) \
ERROR = errval; \
loop()
#define TRY \
if(ERROR == 0)
#define CATCH(err) \
else if(err == ERROR)
#define FINALLY \
if(ERROR != 0)
#define OUT_OF_MEMORY 1
int ERROR = 0;
void random_routine() {
if(/*something goes wrong*/) {
THROW(OUT_OF_MEMORY);
}
}
void start() { Serial.begin(9600); }
void loop() {
TRY {
random_routine();
} CATCH(OUT_OF_MEMORY) {
Serial.println("out of memory");
} FINALLY {
while(true);
}
}
现在你可能不会立即看到这里的技巧,所以这是你在预处理后得到的:
void random_routine() {
if(/*something goes wrong*/) {
ERROR = 1;
//this call is the body of my exception handling solution
//and the question is about this as well
loop();
}
}
void start() { Serial.begin(9600); }
void loop() {
///TRY-s macro result
if(ERROR == 0) {
random_routine();
///chainable CATCH blocks
} else if(ERROR == 1) {
Serial.println("Out of memory");
}
///FINALLY block
if(ERROR != 0) {
while(true);
}
}
所以我的问题是,如果由于某种原因内存满了,函数调用是否能够执行?因为 THROW 宏将始终以这种方式调用 loop(),我的想法是从当前上下文 'escape' 进入无限循环
抱歉我的英语不好
所以,如果你想退出一个函数,回到原来的地方,你应该离开这个函数,而不是调用原来的函数!通过从函数返回,或使用 setjmp
和 longjmp
.
而且在所有情况下,您还需要担心 "how does data get cleaned up"。换句话说,如果你分配了内存,那么你需要在离开函数之前释放它,或者你已经打开了一个文件,你需要关闭它等等。
这些事情正是 RAII 原则派上用场的地方,但它假设您将函数留在编译器的知识范围内,而不是您只是跳回主循环而不进行清理。迟早会出问题。
另请注意,堆栈溢出的行为是未定义的行为 - 它可能会立即使程序崩溃,或者可能导致堆被覆盖,格式化您的 harddrive/SD 卡,或者可能导致守护进程运行从你的鼻子里出来。或者你能想到的任何其他东西,然后是一些。它是未定义的,你不能依赖它做任何特别的事情——只是 "you're not supposed to do that".