代码之家  ›  专栏  ›  技术社区  ›  ilya1725

Qt:更新QString时自动生成的代码失败

  •  1
  • ilya1725  · 技术社区  · 7 年前

    我正在修改用Qt编写的GUI代码( LibrePilot ). 有一种方法可以添加用户类。它们是根据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>
    <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;
    

    的代码 是一样的。 这个错误在我们使用旧版本的gcc之前没有发生过。当前版本是7.2。

    任何人都知道错误发生的原因以及如何优雅地修复它。 谢谢您。

    1 回复  |  直到 7 年前
        1
  •  0
  •   Kuba hasn't forgotten Monica    7 年前

    代码是自动生成的,这与问题无关。你要说的是,你有一个很短的代码片段可能会失败:把它移到一个单独的 main.cpp __attribute__((packed)) 本质上你是善意的要求编译器给你一些未定义的行为-你不需要那个属性,因为它的工作方式不是你认为它工作的方式。此属性的正确实现不应生成成员未充分对齐的记录,因此可能仍会添加特定于平台的填充-您只是假设它不会。无论如何: QString 不是可以转储到磁盘的内容,因此打包此结构毫无意义。在某些情况下,Gcc错误地实现了这个属性,这可能会导致您观察到的行为,尽管在您显示的结构的特定情况下不是这样。可能是其他一些压缩结构破坏了程序状态,导致了您看到的崩溃。首先:制作一个独立的测试用例。然后我们就能知道出了什么问题。但最重要的是: 不使用 __attribute__((packed) 如果要序列化/反序列化二进制数据,请使用 QDataStream