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

3

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

5个回答

7
BSTR数据类型是标准的COM字符串数据类型。改变长度前缀将使得在不同位数进程之间安全地移动字符串变得不可能(或者至少会使其变得更加复杂)。由于COM是唯一相关的跨位数Interop基础设施,因此需要让BSTR在32位进程和64位进程中表现出相同的行为。
这是一个权衡,在限制2GB的情况下,可以轻松地在不同位数的进程之间传递字符串。

谢谢。我没有意识到可以在32位和64位进程之间传递BSTRs。 - Alexander Chertov
1
一个BSTR如何在32位和64位进程之间传递而不需要重新分配? - David Heffernan
2
@David 无论是否重新分配,BSTR的布局都是有文档记录的。自定义和系统提供的编组程序都依赖于这个记录的布局:一个指向数据字符串的指针,紧随其后的是内存中的4字节长度前缀。考虑一个针对在共享内存中保持其状态的对象的优化编组程序。如果该内存映射到两个进程中,则不能为不同位数的BSTR使用不同的内存布局。 - IInspectable

6

一个好的理由是为了与平台API(如MultiByteToWideChar)兼容,该API接受int长度。还有许多使用32位长度的字符串API。

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


1

BSTR是一个长度前缀字符串, 因此第一个属性是长度,而不是地址。因此它不需要与指针大小相同,只需具有足够应用程序所需的大小即可。

对于所有实际目的而言,4GB已经足够了,保持最大字符串大小相同可以让您在进程之间传递字符串时没有问题。例如,如果长度是64位类型,则从64位进程传递8GB字符串到32位进程时会发生什么?应该截断字符串还是报告错误?相同的前缀大小也可以提高向后兼容性。


我已经编辑了这个问题。我的问题是为什么不使用一个size_t而不是4字节的int。 - Alexander Chertov

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接