使用 std::string 作为通用 uint8_t 缓冲区
Posted
技术标签:
【中文标题】使用 std::string 作为通用 uint8_t 缓冲区【英文标题】:Using std::string as a generic uint8_t buffer 【发布时间】:2018-11-25 18:42:32 【问题描述】:我正在查看 Chromium 的源代码,以研究他们如何实现 MediaRecorder API,该 API 将原始麦克风输入流编码/记录为特定格式。
我遇到了interesting codes from their source。简而言之:
bool DoEncode(float* data_in, std::string* data_out)
...
data_out->resize(MAX_DATA_BTYES_OR_SOMETHING);
opus_encode_float(
data_in,
reinterpret_cast<uint8_t*>(base::data(*data_out))
);
...
所以DoEncode
(C++方法)这里接受一个float数组并将其转换为编码字节流,实际操作在opus_encode_float()
(这是一个纯C函数)中完成。
有趣的是,Google Chromium 团队使用std::string
代替std::vector<uint_8>
作为字节数组,他们甚至手动转换为uint8_t 缓冲区。
为什么 Google Chromium 团队的人会这样做,是否存在使用 std::string
对通用字节缓冲区比使用像 std::vector<uint8_t>
等其他缓冲区更有用的情况?
【问题讨论】:
改用std::vectot<uint8_t>
怎么样?
@πάνταῥεῖ 我不是在寻找建议。提到的代码由 Google Chromium 团队完成。我有点想知道他们为什么要这样编码。
真的only differences 是API 的外观以及操作优化。充其量,我们可以推测 Chromium 团队决定他们希望对数据使用字符串操作而不是收集操作。但事情就是这样——这纯粹是猜测。还有一点要记住:仅仅因为它像 Chromium 或 Google 一样多产并不意味着它是完美的。有时,这些项目会做一些奇怪或明显不正确的事情。
@Qix 感谢您的评论。所以毕竟没有理由不使用std::vector
的东西。
【参考方案1】:
Chromium 编码风格(见下文)禁止在没有充分理由的情况下使用无符号整数类型。外部 API 不是这样的原因。有符号和无符号字符的大小都是 1,为什么不呢。
我查看了 opus 编码器 API,似乎早期版本使用签名字符:
[out] data char*: Output payload (at least max_data_bytes long)
虽然 API 现在使用无符号字符,但描述仍然是指有符号字符。所以std::string
for chars 对于早期的 API 来说更方便,并且 Chromium 团队在 API 更新后并没有更改已经使用的容器,他们在一行中使用 cast 而不是更新其他数十行。
整数类型
您不应该使用无符号整数类型,例如uint32_t
,除非有正当理由,例如表示位模式而不是数字,或者您需要定义溢出模2^N
。特别是,不要使用无符号类型来表示一个数字永远不会是负数。相反,为此使用断言。
如果您的代码是一个返回大小的容器,请务必使用能够适应您的容器的任何可能用途的类型。如有疑问,请使用较大的类型而不是较小的类型。
在转换整数类型时要小心。整数转换和提升可能会导致未定义的行为,从而导致安全漏洞和其他问题。
关于无符号整数
无符号整数适用于表示位域和模运算。由于历史意外,C++ 标准还使用无符号整数来表示容器的大小——标准机构的许多成员认为这是一个错误,但实际上目前无法修复。无符号算术不模拟简单整数的行为,而是由标准定义以模拟模算术(围绕上溢/下溢)这一事实,这意味着编译器无法诊断出一类重要的错误。在其他情况下,定义的行为会阻碍优化。
也就是说,混合整数类型的符号性会导致同样大类的问题。我们可以提供的最佳建议:尽量使用迭代器和容器而不是指针和大小,尽量不要混合有符号,并尽量避免无符号类型(表示位域或模运算除外)。不要仅仅使用无符号类型来断言变量是非负的。
【讨论】:
这对我来说很有意义。所以这只是历史和维护的原因。我认为使用std::string
背后可能有一个特殊的秘密:) 非常感谢!
所以,例外的答案是“因为为什么不”?
The Chromium code style forbids using unsigned integral types
有趣;这是有原因的吗?
@Qix Shorty,无符号类型用于位模式。由于无符号类型不能溢出,因此很难诊断溢出问题。请看我更新的答案。
但有符号整数溢出是未定义的。这比定义明确的溢出更可取吗?我在这里没有看到任何具体原因。【参考方案2】:
我们只能理论化。
我的猜测:他们想使用 std::string
中存在但可能不适用于 std::vector<uint8_t>
的内置 SSO 优化。
【讨论】:
对请求的 4000 字节缓冲区进行短字符串优化?以上是关于使用 std::string 作为通用 uint8_t 缓冲区的主要内容,如果未能解决你的问题,请参考以下文章
如何在 C++ 中将 uint8_t 的向量转换为 std::string?