C++ C-API函数的风格
我正在开发一个支持多种编程环境(如VB6和FoxPro)的库。我必须坚持C约定,因为它是最低的公分母。现在我有一个关于风格的问题 假设函数处理输入并返回一个字符串。在此过程中,可能会发生错误。目前提议的样式如下:C++ C-API函数的风格,c++,c,api,C++,C,Api,我正在开发一个支持多种编程环境(如VB6和FoxPro)的库。我必须坚持C约定,因为它是最低的公分母。现在我有一个关于风格的问题 假设函数处理输入并返回一个字符串。在此过程中,可能会发生错误。目前提议的样式如下: int func(input params... char* buffer, unsigned int* buffer_size); 这种风格的好处是原型中包含了所有内容,包括错误代码。并且可以避免内存分配。问题是函数非常冗长。由于缓冲区大小可以是任意的,因此需要更多的代码来实现 另
int func(input params... char* buffer, unsigned int* buffer_size);
这种风格的好处是原型中包含了所有内容,包括错误代码。并且可以避免内存分配。问题是函数非常冗长。由于缓冲区大小可以是任意的,因此需要更多的代码来实现
另一个选项是返回char*,并返回NULL以指示错误:
char* func(input params...);
此样式要求调用方删除缓冲区。内存分配是必需的,因此服务器程序可能会面临内存碎片问题
第二个选项的变体是使用线程局部变量来保存返回的指针char*,这样用户就不需要删除缓冲区
你喜欢哪种款式?原因呢?第二种变体更干净 COM是第二种方法的实现。服务器调用SetErrorInfo来设置出错的详细信息,并返回错误代码。调用方检查代码,并可以调用GetErrorInfo以获取详细信息。调用方负责释放IErrorInfo,但是在第一个变量中传递每个调用的参数也不是很好
服务器可以在启动时预先分配足够的内存,这样它肯定有足够的内存返回错误详细信息。如果必须在显示的两种样式中进行选择,我每次都会选择第一种样式。第二种样式为库的用户提供了一些其他需要考虑的东西,即内存分配,而有人肯定会忘记释放内存。我更喜欢第一种定义,其中传递了缓冲区及其大小。也有例外情况,但通常您不希望在调用函数后进行清理。然而,如果我分配内存并将其传递到函数中,那么我知道我必须自己清理
处理不同大小的缓冲区应该没什么大不了的。第二种风格的另一个问题是,分配内存的上下文可能不同。例如:
// your library in C
char * foo() {
return malloc( 100 );
}
// my client code C++
char * p = foo(); // call your code
delete p; // natural for me to do, but ... aaargh!
这只是问题的一小部分。可以说双方都应该使用malloc&free,但是如果他们使用不同的编译器实现呢?最好所有分配和解除分配都发生在同一个地方。这是否是库r客户端代码取决于您。当其他程序员使用它时,第一版不太容易出错 如果程序员必须自己分配内存,他们更有可能记住释放内存。如果一个库为它们分配内存,这是另一种抽象,可能/将导致复杂性。没有什么值得思考的
- 分配和解除分配应该在同一范围内发生(理想情况下)。最好由调用者传入预先分配的缓冲区。呼叫方可以在稍后安全地释放此内容。这就提出了一个问题——缓冲区应该有多大?我看到在Win32中广泛使用的一种方法是将NULL作为输入缓冲区传递,而
参数将告诉您需要多少size
- 您监督了多少可能的错误情况?返回
可能会限制错误报告的范围char*
- 您希望满足哪些先决条件和后决条件?您的原型是否反映了这一点
- 您是否在呼叫者或被呼叫者中执行错误检查
typedef enum {
RESULT_ONE,
RESULT_TWO
} RESULT;
…因为它提供类型/分配安全性
有一个get last error函数也很好(但是需要中央存储),我个人使用它只是为了提供关于已识别错误的额外信息
备选方案1的详细程度可以通过制作以下简单化合物来限制:
struct Buffer
{
unsigned long size;
char* data;
};
那么您的api可能会看起来更好:
ERROR_CODE func( params... , Buffer* outBuffer );
这一战略也为更复杂的机制打开了大门。例如,假设您必须能够为用户分配内存(例如,如果您需要调整缓冲区大小),t
struct Buffer
{
unsigned long size;
char* data;
void* (*allocator_callback)( unsigned long size );
void (*free_callback)( void* p );
};
int func(char* buffer, size_t buffer_size, input params...);
// Style 1 functions
int fooBuff(char* buffer, unsigned int buffer_size, input params... );
// Style 2 functions
char* fooBuffAlloc(input params...);
bool fooBuffFree(char* foo);