我正在修改用Qt(LibrePilot)编写的GUI代码。有一种添加用户类的方法。它们是根据XML描述自动生成的。
所以这个课:
<xml>
<object name="RecorderService_RecordDescription" singleinstance="true" settings="false" category="State">
<description>For Recorder gadget</description>
<field name="text" units="char" type="string" elements="1"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="false" updatemode="manual" period="0"/>
<telemetryflight acked="false" updatemode="periodic" period="1000"/>
<logging updatemode="periodic" period="100"/>
</object>
</xml>
将自动生成为一个类,该类具有一个包含在结构内部的数据元素,并带有访问该数据元素的方法。
// Field structure
typedef struct {
QString text;
} __attribute__((packed)) DataFields;
当我尝试使用text
方法将setText
设置为新值时:
void RecorderService_RecordDescription::setText(const QString value)
{
mutex->lock();
bool changed = (data_.text != static_cast<QString>(value));
data_.text = static_cast<QString>(value);
mutex->unlock();
if (changed) { emit textChanged(value); }
}
我得到SIGABRT
例外。
#0 0x00007ffff509ce97 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff509e801 in __GI_abort () at abort.c:79
#2 0x00007ffff50e7897 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff5214b9a "%s\n") at ../sysdeps/posix/libc_fatal.c:181
#3 0x00007ffff50ee90a in malloc_printerr (str=str@entry=0x7ffff5212d88 "free(): invalid pointer") at malloc.c:5350
#4 0x00007ffff50f5e1c in _int_free (have_lock=0, p=0x7ffff5f8c5f0, av=0x7ffff5449c40 <main_arena>) at malloc.c:4157
#5 0x00007ffff50f5e1c in __GI___libc_free (mem=0x7ffff5f8c600) at malloc.c:3124
#6 0x00007fffc798671e in RecorderService_RecordDescription::setText(QString) () at /usr/lib/librepilot-gcs/plugins/LibrePilot/libUAVObjects.so
我发现的一个解决方案是,如果我向RecorderService_RecordDescription
添加另一个字段。即XML是这样的:
<xml>
<object name="RecorderService_RecordDescription" singleinstance="true" settings="false" category="State">
<description>For Recorder gadget</description>
<field name="text" units="char" type="string" elements="1"/>
<field name="seconds" units="sec" type="uint32" elements="1"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="false" updatemode="manual" period="0"/>
<telemetryflight acked="false" updatemode="periodic" period="1000"/>
<logging updatemode="periodic" period="100"/>
</object>
</xml>
错误消失了。自动生成的类具有以下数据结构:
// Field structure
typedef struct {
quint32 seconds;
QString text;
} __attribute__((packed)) DataFields;
setText
的代码是相同的。
在使用旧版gcc之前,没有发生此错误。当前版本是7.2。
任何人都知道为什么会发生错误以及如何优雅地修复它。 谢谢。
答案 0 :(得分:0)
代码自动生成的事实与问题无关。您的意思是,您有一个非常短的代码片段,据说该片段失败了:将其移动到单独的main.cpp
作为测试用例!我敢打赌,您在代码中还有其他问题,这就是为什么它会失败。您遇到的问题之一是__attribute__((packed))
本质上是请编译器提供一些未定义的行为-您不需要该属性,因为它的工作方式并非您认为的工作方式。正确实现此属性不应生成成员对齐不充分的记录,因此可能仍添加了特定于平台的填充-您只是假设不会。而且无论如何:QString
并不是可以转储到磁盘的东西,因此打包此结构没有任何意义。在某些情况下,Gcc错误地实现了此属性,这可能会导致您观察到的行为,尽管在显示的结构的特定情况下并非如此。可能其他一些压缩结构最终破坏了程序状态并导致了崩溃。首先:制作一个独立的测试用例。然后我们可以找出问题所在。但是,最重要的是:请勿使用__attribute__((packed)
。它的典型用法是:序列化。如果要对二进制数据进行序列化/反序列化,请使用QDataStream
或类似的机制。