我正在查看一些代码(实际上是ArduPilot),将它作为我自己的东西的灵感。现在我觉得我发现了一个主要的错误 - 但是在大声喊叫之前;)也许有人可以帮助我检查一下我是否误解了C ++。
有一种方法(我简化了它):
void GCS_MAVLINK::update(void) {
// receive new packets
mavlink_message_t msg;
mavlink_status_t status;
// process received bytes
while (data_available()) {
uint8_t c = receive_data();
// Try to get a new message
if (parse_and_accumulate(c, &msg, &status)) {
handleMessage(&msg);
}
}
}
定期调用此方法。它从缓冲区读取数据直到耗尽,将其抛出到外部解析函数以及引用最终消息和状态结构以通过副作用更新,并且每次解析器看到消息完成时,消息都被消耗。
到目前为止一切顺利。如果缓冲区在消息中间空白,会发生什么?好的,其余的可能会在下一次计划的调用时到达缓冲区。但是分配的本地/堆栈会发生什么!消息和状态变量?据我所知,在此期间,它们可能已经被堆栈使用中的各种垃圾所覆盖。堆栈指针甚至可能已经移位。
在我愚弄自己之前,有人可以帮我确认这里似乎有一个重大问题。
另外,如果我通过使msg和status变量为静态来“修复”它,它们对于包含该方法的类的每个实例仍然是分开的,对吗?
此致 索伦
答案 0 :(得分:3)
如果缓冲区在消息中间空白,会发生什么?
据推测,parse_and_accumulate
应该将输入字节存储在某处,与输出消息参数分开,直到消息准备好;并且只有写入该参数。如果该函数假定消息对象将在调用之间保留,并且没有看到该函数,那么只有一个错误是无法告诉。
但是分配的本地/堆栈会发生什么! msg和状态变量?
正如你所说,当函数退出时它们会被破坏。 如果 parse_and_accumulate
将它们用作持久存储,那么你就有一个bug,因为它们不是持久的;希望它没有,但这个假设几乎肯定是应该修复的内容。
另外,如果我通过使msg和status变量为静态来“修复”它,它们对于包含该方法的类的每个实例仍然是分开的,对吗?
让他们static
不会解决任何问题;由于不可重入,它可能只会导致模糊的错误。如果您没有向我们展示的功能是错误的,那么这就是需要修复的内容。
如果你将它们static
(无论是局部变量还是类成员),那么每个只有一个实例。如果它们确实需要持久化并与对象相关联,那么它们必须是非静态类成员;但他们几乎肯定不应该这样。
答案 1 :(得分:0)
在我愚弄自己之前,有人可以帮我确认这里似乎有一个重大问题。
可能有也可能没有问题。只显示你展示的代码真的不可能。
如果缓冲区在消息中间空白,会发生什么?好的,其余的可能会在下次预定的调用时到达缓冲区。
在声称存在错误之前,您需要确保实际发生这种情况。看起来你所展示的代码看起来并不像是为了解决这个问题,但也许它不需要?
不,他们不会。它们还会使您的代码不可重入且不是线程安全的。另外,如果我通过使msg和status变量为静态来“修复”它,它们对于包含该方法的类的每个实例仍然是分开的,对吗?
答案 2 :(得分:0)
再次查看parse_and_accumulate的来源之后,我现在看到确实在调用之间存储数据。参数struct仅用于将完成的消息返回到..
所以我的坏 - 抱歉。谢谢你的帮助!