2010-01-19 53 views
5

C API函数分配它们的输出还是让用户指定输出缓冲区是一个好主意吗?例如:API设计 - 分配输出?

BOOL GetString(
    PWSTR *String 
    ); 
... 
PWSTR string; 
GetString(&string); 
Free(string); 

VS

BOOL GetString(
    PWSTR Buffer, 
    ULONG BufferSize, 
    PULONG RequiredBufferSize 
    ); 
... 
// A lot more code than in the first case 

更具体我不知道为什么在Win32 API主要使用第二种情况下(例如GetWindowTextLookupAccountSid)。如果一个API函数知道输出有多大,为什么用户会尝试猜测输出大小?我找不到有关为什么会使用第二种情况的任何信息。

另外:LookupAccountSid示例特别糟糕。它在内部使用LSA API,它为调用者分配输出。然后,LookupAccountSid可以让用户分配一个缓冲区(并猜测正确的缓冲区大小),只要它可以返回LSA的输出!为什么?

+0

这取决于。这两个习语都被使用。两者都有优点和缺点。 – 2010-01-19 00:51:42

+0

除了能够使用基于堆栈的缓冲区之外,第二种情况的优点是什么? – wj32 2010-01-19 00:53:50

+0

它允许调用者使用他们的分配器的选择。如果您分配内存并将其留给主叫方以释放,则主叫方需要使用相应的取消分配器 - 这可能不是他们的偏好。填充调用者提供的缓冲区允许他们为他们的目的选择合适的分配器,而不是依赖API选择的分配器。 – 2010-01-19 01:08:54

回答

5

Win32 API不预先分配缓冲区,因为它想让调用代码选择如何提供缓冲区。它允许他们提供堆栈和各种基于堆的缓冲区。有几个地方会提前知道缓冲区的最大尺寸,开发人员希望使用基于堆栈的缓冲区的简单性。

文件系统是路径不会超过MAX_PATH的最佳示例。所以,而不是分配+免费。开发人员只需声明一个基于堆栈的缓冲区。

使C API分配内存的好处是它简化了调用模式。 Win32模式的不利之处在于,你最终多次调用API两次。第一次确定缓冲区的大小,然后第二次使用适当大小的缓冲区。使用API​​分配的缓冲区只需要一次调用。

但是,不利的一面是,你拿走了来电者的分配选择。此外,您必须传达您的选择,以便他们正确释放API(例如,窗口可以从多个不同的地方分配)。

+3

我会注意到,将两个调用和分配放在自己的函数中非常简单,简化调用模式是一个非常小的问题。如果你只提供一个版本的API,它必须是更灵活的。 – 2010-01-19 01:51:55

1

第二种方法有像

  • 它可以让呼叫者管理内存分配的生命周期
  • 它可以让呼叫者重用为遵循相同的模式
  • 它可以让呼叫者不同的呼叫分配的内存的优势决定提供哪个缓冲区,例如堆栈或堆。