我目前正在开发一个C ++ dll,它会向调用者返回一个字符串。为了使dll独立于构建过程的其余部分,以及C ++缺少标准ABI,我不得不用C char指针包装字符串。
据我所知,有两种以普通C方式返回字符串的可能性:
//Method 1
bool Foo1(wchar_t* s1, int len)
{
//Needs space for 6 chars + null terminator
if (len < 7)
return false;
wcscpy(s1, L"Hello1");
return true;
}
//Method 2
wchar_t* Foo2()
{
wchar_t* s2 = new wchar_t[10];
wcscpy(s2, L"Hello2");
return s2;
}
//Caller
int _tmain(int argc, _TCHAR* argv[])
{
wchar_t s1[10];
bool res = Foo1(s1, sizeof(s1) / sizeof(WCHAR));
wchar_t* s2 = Foo2();
delete s2;
return 0;
}
是否存在任何有利于这两种解决方案之一的指南?我已经看到方法1主要用于Windows API,可能是由于历史原因。但是,我也没有看到使用第二种方法的任何负面影响,这消除了调用者事先分配内存的需要。唯一的缺点是释放分配的内存的责任现在掌握在调用者的手中。谢谢你的建议。
答案 0 :(得分:3)
您不希望DLL中的new
字符串只返回它们。您还需要提供一个释放函数,调用者可以使用该函数来释放。如果调用者的delete[]
实现与DLL的new[]
实现相匹配,那么您根本不需要降低到C级别,只需使用std::string
。
正如您所指出的,另一种方法是让调用者提供缓冲区。
第三种选择是让呼叫者提供分配机制。
第四种方法是使用Windows专用分配机制来完成这项任务,即BSTR
字符串,SysAllocString
和朋友。
而不是纯C风格的DLL,如果这似乎是必要的,我会把它变成一个COM服务器。用g ++做这件事很麻烦。所以,如果我还要支持g ++,我可能会做一个纯C DLL并使用提到的BSTR
内容。
顺便说一句,除了硬核遗留代码之外,没有理由使用Microsoft的古老和非标准_tmain
和_TCHAR
内容。对于一种弱Windows 9x兼容性而言,这个宏的东西在2000年已经过时,随着Layer for Unicode的引入。所以,糟糕的坏事和已经过了15年了。
答案 1 :(得分:1)
第三种方法:
inline char* calloc_buffer(void*,unsigned n){ return (char*)calloc(1,n);}
char* get( char*(*make_buff)(void*,unsigned n), void* );
包括一个让调用者分配缓冲区的回调,以及调用者可以传递给它们调用它的函数。这样可以实现最高效率如果他们愿意,他们也可以使用本地缓冲区,如果不够大,也可以使用calloc
。具有偏移和长度的版本也很有用。
接下来,对于高质量的C ++便携式dll,我们包含可选的仅包头包装器:
inline char* from_vector(void*v_,unsigned n){
auto v =static_cast<std::vector<char>*>(v_);
v->resize(n);
return v->data();
}
inline std::vector<char> get(){
std::vector<char> buf;
get( from_vector, &buf );
return buf;
}
它为您提供接近最佳C代码的最佳C ++。
答案 2 :(得分:0)
这取决于。第二个使得返回错误条件变得更加困难,您可能需要考虑这些条件。当然你可以使用errno来克服这个问题。最重要的是,没有对错,如果它是您自己的应用程序,它与您正在使用的代码风格或您的个人偏好相匹配。