使用P / Invoke时设置StringBuilder.Capacity的正确方法是什么?

时间:2010-10-30 02:33:47

标签: .net pinvoke stringbuilder

StringBuilder.Capacity是否应设置为最大.NET字符数,而不考虑空终止,或者在使用P / Invoke时,必须将其设置为更高,以便为空终止符保留空间。

自然的反应是它应该设置得更高,但似乎P / Invoke应该自动补偿。事实上,这实际上是在这里记录的:http://msdn.microsoft.com/en-US/library/s9ts558h(v=VS.100).aspx

这个问题的原因是大多数例子与上述文件并不严格一致。它们几乎总是被编码:

StringBuilder sb = new StringBuilder(dotNetChars + 1);
SomeWindowsAPI(sb, sb.Capacity);

而不是:

StringBuilder sb = new StringBuilder(dotNetChars);
SomeWindowsAPI(sb, sb.Capacity + 1);

(我意识到一些API处理缓冲区大小参数的方式不同。假设API处理这种必须通用的方式,如GetFullPathNamehttp://msdn.microsoft.com/en-us/library/aa364963(v=VS.85).aspx

在API调用中直接使用带有sb.Capacity的表达式似乎是避免不匹配的最佳做法。问题是添加+1是否正确。

环顾四周。您可能会发现显示sb.Capacity + 1的唯一位置是MSDN文档。

当然,人们可以在谨慎的情况下使用比绝对必要的更大的缓冲区来分配,但我想知道如何做到这一点的共识。

3 个答案:

答案 0 :(得分:4)

我已经意识到你已经有了五年的答案,但在我看来他们并没有真正回答这个问题,他们基本上没有检查这个潜在的问题,而没有检查这样做是否正确。

MSDN文档保证marshaller将确保有足够的空间来存储Capacity的完整StringBuilder以及额外的空终止符。引用Default Marshaling for Strings

  

固定长度字符串缓冲区

     

[...]

     

解决方案是传递StringBuilder缓冲区作为参数而不是字符串。 StringBuilder 可以被被调用者取消引用和修改,前提是它不超过 StringBuilder 的容量。它也可以初始化为固定长度。例如,如果将 StringBuilder 缓冲区初始化为 N 的容量,则封送程序会提供大小为( N +1)个字符的缓冲区。 +1表示非托管字符串具有空终止符而 StringBuilder 不具有空终结符。

     

[...]

所以你不必担心增加一个容量,编组人员已经为你做了这个。

答案 1 :(得分:0)

StringBuilder的构造函数中,容量使用如下:

m_ChunkChars = new char[capacity];

这与m_ChunkLength字段一起用于确定StringBuilder的内容。这仅描述实际字符,不包括终止字符。

所以你的回答是没有必要+ 1

答案 2 :(得分:0)

可能有一定数量的货物崇拜节目正在进行中。当被问及为字符串分配的内存时,有人会回答习惯,即回答“长度+ 1”而不是长度。开发人员只是“在安全方面犯错误”并且传递长度为+1,而不是阅读有关为字符串分配内存的新情况的文档,而读取该代码的其他人推断出相同的规则和实践传播。从一个人传到另一个人,合理地可能是正确的,而不是有害的,不一定是正确的。