为啥在 64 位平台上 BSTR 长度前缀为 4 个字节?

Posted

技术标签:

【中文标题】为啥在 64 位平台上 BSTR 长度前缀为 4 个字节?【英文标题】:Why is BSTR length prefix 4 bytes on 64-bit platforms?为什么在 64 位平台上 BSTR 长度前缀为 4 个字节? 【发布时间】:2014-05-30 16:38:41 【问题描述】:

似乎在 64 位平台上使用 8 字节长度的前缀是合理的。如果我们可以处理超过 4Gb 的内存,为什么不允许使用 5Gb 字符串?答案只是“按规范”还是有一些我不知道的互操作性/向后兼容性原因? 谢谢。

【问题讨论】:

【参考方案1】:

BSTR 数据类型是标准的 COM 字符串数据类型。更改长度前缀将无法在不同位数的进程之间安全地移动字符串(或至少使其复杂得多)。由于 COM 是唯一相关的跨位互操作基础架构,因此必须让 BSTRs 以相同的方式处理 32 位进程和 64 位进程。

这是一种折衷,强加 2GB 的“限制”以换取在不同位数的进程之间轻松编组字符串。

【讨论】:

谢谢。我没有意识到您可以在 32 位和 64 位进程之间传递 BSTR。 如何在不重新分配的情况下将 BSTR 从 32 位传递到 64 位进程? @David 是否重新分配,BSTR 的布局已记录在案。自定义和系统提供的编组器都依赖于这种记录在案的布局:指向数据字符串的指针,该数据字符串紧接在内存中该数据之前的 4 字节长度前缀。考虑一个优化的编组器,用于将其状态保存在共享内存中的对象。如果该内存被映射到两个进程中,则您不能让BSTRs 具有针对不同位数的不同内存布局。【参考方案2】:

一个很好的理由是与平台 API 兼容,例如接受 int 长度的 MultiByteToWideChar。还有更多使用 32 位长度的字符串 API。

这实际上并不是一个真正的限制,因为我无法想象长度 >2GB 的BSTR 将是解决问题的最佳方案。

【讨论】:

【参考方案3】:

BSTR 是 length-prefixed string,所以第一个属性是 length,而不是地址。因此,它不必与指针的大小相同,可以是对应用程序足够的大小

对于所有实际用途,4GB 对于一个字符串来说绰绰有余,并且保持最大字符串大小相同可以让您在进程之间毫无问题地传递字符串。例如,如果长度是 64 位 Windows 上的 64 位类型,那么当您将 8GB 字符串从 64 位进程传递到 32 位进程时会发生什么?字符串应该被截断还是应该报告错误?相同的前缀大小也可以提高向后兼容性

【讨论】:

我已经编辑了这个问题。我要问的是为什么没有 size_t 而不是 4 字节的 int。【参考方案4】:

拥有大量总大小超过 2GiB 的对象的应用范围远大于任何单个对象超过 2GiB 的应用范围。即使对 64 位值的单个操作并不比对 32 位值的操作更昂贵,适合每个缓存级别的 32 位值的数量也将是 64 位值数量的两倍。因此,在没有充分理由使用 64 位值来保存对象大小的情况下,将单个对象的平台限制为 2GiB 是一个完全合理的设计决策,尤其是因为不是设计的代码 如果在不拒绝创建大于 2GiB 的对象的尝试的系统上运行,则使用较大的对象通常会以容易产生安全漏洞的方式出现故障。

【讨论】:

【参考方案5】:

最重要的原因大概是为了让BSTR可以继续在VARIANT旅行。您会从 oaidl.h 中tagVARIANT 的定义中注意到bstrVal 成员似乎是其他类型联合的一部分,但它的长度存储在哪里?答案在内存中紧接在bstrVal 成员之前的VARIANT 结构的wReserved2/wReserved3 成员中。那里有 3 个保留字,所以理论上 BSTR 的长度可以扩展到 6 个字节,但如果它变得更大,它将覆盖 VARTYPE 成员并且 VARIANT 将不再工作。所以BSTR 即使在 64 位平台上也有长度限制,因此它可以继续在VARIANT 中传播。

【讨论】:

以上是关于为啥在 64 位平台上 BSTR 长度前缀为 4 个字节?的主要内容,如果未能解决你的问题,请参考以下文章

前端js实现 blob转base64位 和 base64位转blob

为啥在 64 位 5s iPhone 上安装时应用程序会卡住

为啥在 x64 Java 中 long 比 int 慢?

为啥 GOlang的float型后面要加32或64?

64位平台上,函数返回指针时遇到的段错误问题

ipv4 ipv6哪个上网速度快