从C中的函数返回char数组的首选方法

时间:2014-06-15 21:01:05

标签: c++ c windows winapi

我目前正在开发一个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,可能是由于历史原因。但是,我也没有看到使用第二种方法的任何负面影响,这消除了调用者事先分配内存的需要。唯一的缺点是释放分配的内存的责任现在掌握在调用者的手中。谢谢你的建议。

3 个答案:

答案 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来克服这个问题。最重要的是,没有对错,如果它是您自己的应用程序,它与您正在使用的代码风格或您的个人偏好相匹配。