复制宽字符串

Duplicating wide-character string

我正在尝试创建一个应用程序,在该应用程序中我有一个函数,我正在尝试复制一个宽字符串。我目前正在使用 _wcsdup(),因为它是一个 Windows 应用程序,并且一切正常。但是我需要创建一个多平台函数,所以 _wcsdup()(这是一个 Windows 函数)对我来说不可行。

现在,我的代码看起来像这样:

wchar_t* out = _wcsdup(wstring.str().c_str());

其中 wstring 是字符串流。

现在,我正在寻找 Windows 和 Linux 的通用函数,以使该函数正常工作。

标准的跨平台等效项是 allocate/free 使用 new[]/delete[]wchar_t[] 缓冲区(或者,如果绝对需要,malloc() /free() 以反映 _wcsdup() 的行为),使用 std::copy()std::memcpy() 将字符从 wstring 复制到该缓冲区,例如:

std::wstring w = wstring.str();
wchar_t* out = new wchar_t[w.size()+1];
std::copy(w.begin(), w.end(), out);
w[w.size()] = L'[=10=]';
...
delete[] out;

/*
std::wstring w = wstring.str();
wchar_t* out = (wchar_t*) malloc((w.size() + 1) * sizeof(wchar_t));
std::copy(w.begin(), w.end(), out);
w[w.size()] = L'[=10=]';
...
free(out);
*/
std::wstring w = wstring.str();
size_t size = w.size() + 1;
wchar_t* out = new wchar_t[size];
std::memcpy(out, w.c_str(), size * sizeof(wchar_t));
...
delete[] out;

/*
std::wstring w = wstring.str();
size_t size = (w.size() + 1) * sizeof(wchar_t);
wchar_t* out = (wchar_t*) malloc(size);
std::memcpy(out, w.c_str(), size);
...
free(out);
*/

但是,无论哪种方式,因为 str() returns 一个 std::wstring 开始,你最好坚持使用 std::wstring 而不是使用 wchar_t* 全部:

std::wstring out = wstring.str();

如果你需要 (const) wchar_t*,你可以使用 out.c_str()out.data(),例如当将 out 传递给采用空终止字符串的 C 风格函数时指针。

假设需要将字符串传递给期望 free 它的函数,您可以使用 mallocmemcpy:

auto const ws = wstring.str();
auto const ptr = std::malloc(sizeof wchar_t * (ws.size() + 1));
std::memcpy(ptr, ws.c_str(), sizeof wchar_t * (ws.size() + 1));
// pass ptr to another function, or std::free(ptr)

+ 1是考虑空终止符,size()中没有。

传统的方法是在你的程序中有一个配置系统,告诉你平台有什么和没有什么:

在一些专门用于可移植性的源文件中,您有:

#if !HAVE_WCSDUP
wchar_t *wcsdup(const wchar_t *orig)
{
  #if HAVE_MICROSOFT_WCSDUP
    return _wcsdup(orig);
  #else
    size_t nwch = wcslen(orig) + 1;
    wchar_t *copy = wmalloc(nwch);
    if (copy)
      wmemcpy(copy, orig, nwch);
    return copy;
  #endif
}
#endif

在一些头文件(也包括在上面)中,你有这个:

#if !HAVE_WSCDUP
extern "C" wchar_t wcsdup(const wchar_t *);
#endif

提供缺少的声明。一种可能的方法也是这样。在头文件中,你做:

#if HAVE_WCSDUP
// nothing to provide
#elif HAVE_MICROSOFT_WCSDUP
// just alias to the Microsoft one via #define
#define wcsdup _wcsdup
#else
// declare ours: provided in portability.cc
extern "C" wchar_t wcsdup(const wchar_t *);
#endif

然后在portability.cc:

#if !HAVE_WCSDUP && !HAVE_MICROSOFT_WCSDUP
wchar_t *wcsdup(const wchar_t *orig)
{
  size_t nwch = wcslen(orig) + 1;
  wchar_t *copy = wmalloc(nwch);
  if (copy)
    wmemcpy(copy, orig, nwch);
  return copy;
}
#endif

您需要围绕您的程序构建配置系统来提供这些 HAVE_ 常量的值。在某些系统上,shell 脚本可以检查环境并将它们扔到 config.h 中。对于某些系统,您可以使用固定配置;例如在 Windows 上构建的配置步骤可能包括将手动维护的 config-msvc.h 复制到 config.h。在 config-msvc.h 你有:

#define HAVE_MICROSOFT_WCSDUP 1

我假设您需要一个 malloc 重复的字符串,因为与一些消耗一个的 API 进行通信。因此,在我的回答中,我没有自以为是地使用 C++ 库功能来解决问题。

然而,在 C++ 代码中,我们可能应该将 C 函数称为 std::wcslen 等等。或者 portability.cc 可以只是 portability.c,如果它提供缺少的 C 函数。