【问题标题】:Does QVariant expect a null-terminated QByteArray?QVariant 是否需要一个以 null 结尾的 QByteArray?
【发布时间】:2013-08-10 18:14:32
【问题描述】:

我需要从 QByteArray 构造一个 QVariant 对象。 QVariant 构造函数 QVariant(const QByteArray & val) 是否期望 QByteArray 中的原始字节以空值结尾?

背景信息:

我的 QByteArray 对象是用 QByteArray::fromRawData(const char * data, int size) 构造的,并且不是以空值结尾的。

我的目标是使用 QSqlQuery::bindValue() 将 QByteArray 对象中的原始字节复制到数据库中,该数据库期望 Qvariant 对象作为其参数之一。

我的猜测是 QByteArray 中的字节必须以空值结尾。我看不到如何实现 QVariant(const QByteArray & val) 构造函数。

非常感谢!

【问题讨论】:

    标签: qt


    【解决方案1】:

    添加到 QByteArray 中的字节可能会或可能不会以 0 结尾。如果将 QByteArray 转换为 QVariant,它将包含已添加到数组中的所有字节,而不管它们的值如何。这是可能的,因为 QByteArray 存储字节数。当您拥有char* 指针和字节数时,您可以安全地操作字节,而无需知道那里是否有 0。

    实际上,当您调用data() 获取char* 指针时,数据总是以空值结尾的。但它确实在幕后。如果您使用data() 并将该指针传递给某个没有大小的函数,0-终止将保护您免受段错误的影响。但这对您的问题并不重要。

    我会尝试用例子来说明这一点。

    Raw data: 1 2 3 4 ....
    calling fromRawData(pointer, 4)
    QByteArray contents: 1 2 3 4
    Underlying QByteArray's buffer contents: 1 2 3 4 0 ...
    
    Raw data: 1 2 3 0 ....   
    calling fromRawData(pointer, 4)
    QByteArray contents: 1 2 3 0
    Underlying QByteArray's buffer contents: 1 2 3 0 ...
    
    Raw data: 1 0 2 3
    calling fromRawData(pointer, 4)
    QByteArray contents: 1 0 2 3
    Underlying QByteArray's buffer contents: 1 0 2 3 0 ...
    

    并且 QVariant 将包含与“QByteArray 内容”相同的字节。

    【讨论】:

    • 实际上,问题在于将 QByteArray 加载到 QVariant 中。由于它是通过 const 变量执行的,因此它不会进行深层复制,并且您不能确定是否会有 '\0'。 IE。您可以链接 constData() 调用并在最后获得一个非空终止的数组。检查我发布的要点..
    • 即使从 const 变量也可以进行深度复制(例如,QString::QString(const QString &other) 会按照文档中的说明进行深度复制)。我怀疑深拷贝内部变量是可变的。但这也无所谓。 QVariant 复制整个 QByteArray 值。它不关心它的底层缓冲区。构造时它不会调用constData。此外,您不能链接toByteArray().constData() 调用,因为constData 返回的缓冲区仅在源对象被销毁之前有效,并且对象是临时的并且立即被销毁。
    • 在第 8 行的示例中,您能否确认您没有犯错?我认为 QByteArray 内容将是 1 2 3 0 0 对吗?一定是我想的。我的数据实际上会被加密,所以我不一定知道中间某处的某些位组合可能代表空值。所以我认为在你的最后一个例子中,很明显中间可以有一个空值,但它确实是缓冲区内容的一部分。我认为我们可以搁置这个问题。谢谢大家!
    • 我认为 'QByteArray ensures 数据后跟一个 '\0' 终止符'这一事实可能意味着数据时没有添加 '\0'已经 '\0' 终止。但是这个注释是相当迂腐的。这一事实不应影响任何编写良好的代码。
    【解决方案2】:

    为新人编辑。看看 cmets。

    From docs:

    QByteArray 可用于存储原始字节(包括 '\0')和 传统的 8 位以 '\0' 结尾的字符串。使用 QByteArray 很多 比使用 const char * 更方便。 在幕后,它总是 确保数据后跟 '\0' 终止符

    这意味着,即使你不让它为空终止,QByteArray 也会确保它。但只有当它创建一个深拷贝时...检查size()

    int QByteArray::size() 常量

    返回此字节中的字节数 大批。字节数组中的最后一个字节位于 size() - 1 位置。 此外,QByteArray 确保位置 size() 处的字节是 始终为 '\0',以便您可以使用 data() 的返回值和 constData() 作为期望以 '\0' 结尾的函数的参数 字符串。 如果 QByteArray 对象是从原始数据创建的 不包括尾随的空终止字符,然后是 QByteArray 除非创建深层副本,否则不会自动添加它。

    由于 prolly QVariant 将使用 constData() 方法,您不能确定它是否会以空值终止。看this gist

    【讨论】:

    • 令人困惑! QByteArray::fromRawData() 文档末尾给出的警告是否与您以粗体强调的声明相矛盾?此外,警告指出“QByteArray 不获取数据的所有权”,那么它真的在幕后添加 \0 吗?
    • 在我看来,QByteArray 仅在复制或以 QByteArray::fromRawData() 之外的其他方式构造时才添加 '\0'。我认为如果您使用构造函数 QByteArray(const char * data, int size = -1),根据文档,它将进行深层复制,然后在幕后添加 '\0'。我理解正确吗?
    • 查看 data() 示例。它如何总是返回 \0。检查您是如何多保留一个空间的,否则副本会损坏
    • 所以你建议 QVariant 构造函数使用 QByteArray::data() 函数?可能是,在这种情况下,我不需要自己将 '\0' 添加到 QByteArray 的末尾。如果有人能证实这一点,那就太好了。
    • 注意构造函数 QVariant(const QByteArray & val) 需要一个 const 参数?意味着你不能使用 QByteArra::data() 因为这个函数不是 const。然后它必须使用 QByteArra::constData() 并且这个函数的文档说:“除非 QByteArray 对象是从原始数据创建的,否则数据是'\0'-终止的。”所以我们回到我们开始的地方 - 构造函数 QVariant(const QByteArray & val) 是否期望 QByteArray 中的原始字节以空值结尾?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-15
    • 1970-01-01
    • 1970-01-01
    • 2012-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多