【问题标题】:Null bytes in char* in QByteArray with QDataStream带有 QDataStream 的 QByteArray 中的 char* 中的空字节
【发布时间】:2014-07-29 12:09:51
【问题描述】:

我发现QByteArray 中的char* 有空字节。代码:

QByteArray arr;
QDataStream stream(&arr, QIODevice::WriteOnly);
stream << "hello";

查看调试器变量视图:

我不明白为什么我的开头有三个空字节。我知道 [3] 字节是字符串长度。我可以删除最后一个字节吗?我知道它是以 null 结尾的字符串,但对于我的应用程序,我必须有原始字节(在开始时有一个字节作为存储长度)。

对我来说更奇怪的是当我使用 QString 时:

QString str = "hello";
[rest of code same as above]
stream << str;

最后没有空值,所以我认为在每个 char 通知下一个字节是 char 之前可能是空字节?

只有两个问题:

  1. 为什么会有这么多空字节?
  2. 如何删除它,包括最后一个空字节?

【问题讨论】:

  • QStrings 是 16 位 unicode 字符串 - 这就是为什么您在第二个示例中看到每个字符 2 个字节的原因。

标签: c++ qt


【解决方案1】:

我不明白为什么我的开头有三个空字节。

它是一个固定大小的 uint32_t(4 字节)标头。它是四个字节,因此它可以指定数据长度只要 (2^32-1) 字节。如果它只有一个字节,那么它只能描述最长 255 个字节的字符串,因为这是一个字节可以容纳的最大整数值。

我可以删除最后一个字节吗?我知道它是以 null 结尾的字符串,但对于我的 应用程序我必须有原始字节(开始时有一个字节 存储长度)。

当然,只要稍后解析数据数组的代码不依赖尾随 NUL 字节的存在才能正常工作。

对我来说更奇怪的是当我使用 QString [...] 它最后没有 null,所以我认为在每个 char 通知下一个字节是 char 之前可能是 null 字节?

根据Qt serialization documentation page,QString 被序列化为:

- If the string is null: 0xFFFFFFFF (quint32)
- Otherwise:  The string length in bytes (quint32) followed by the data in UTF-16.

如果你不喜欢这种格式,而不是直接序列化 QString,你可以做类似的事情

stream << str.toUtf8();

相反,您的 QByteArray 中的数据将采用更简单的格式 (UTF-8)。

为什么会有这么多空字节?

当被编码的长度值很小时,它们用于固定大小的头字段;或表示以 NUL 结尾的 C 字符串的结尾。

如何删除它,包括最后一个空字节?

你可以像这样以你喜欢的格式添加字符串(没有 NUL 终止符,但只有一个长度的头字节):

const char * hello = "hello";
char slen = strlen(hello);
stream.writeRawData(&slen, 1);
stream.writeRawData(hello, slen);

...但如果您有选择,我强烈建议您将 NUL 终止符字节保留在字符串的末尾,原因如下:

  1. 单个前面的长度字节会将您的字符串长度限制为 255 个字节(或更少),这是一个不必要的限制,将来可能会困扰您。

  2. 避免使用 NUL 终止符字节实际上并没有节省任何空间,因为您添加了一个字符串长度字节来进行补偿。

  3. 如果存在 NUL 终止符字节,您可以简单地将指向字符串第一个字节的指针直接传递给任何需要 C 样式字符串的代码,并且它将能够立即使用该字符串 (无需任何数据转换步骤)。如果您改用不同的约定,则最终必须先复制整个字符串,然后才能将其传递给该代码,以便您可以将 NUL 字节附加到字符串的末尾,以便期望 C 字符串的代码可以使用它。这将导致 CPU 效率低下且容易出错。

【讨论】:

  • 谢谢你的解释,现在我明白了。此外,writeRawData 工作正常 :) 遗憾的是,我必须删除 NUL 终止符,因为以这种方式创建的数据将由 TCP 以特定的恒定格式发送到服务器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
  • 2014-06-09
  • 2023-03-08
  • 2019-05-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多