【问题标题】:Duplicating wide-character string复制宽字符串
【发布时间】:2021-10-18 17:44:58
【问题描述】:

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

现在,我的代码如下所示:

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

其中wstring 是一个字符串流。

现在,我正在寻找一个适用于 Windows 和 Linux 的通用功能,以使该功能正常工作。

【问题讨论】:

  • 你为什么不用std::copy
  • 为什么不std::wstring out = wstring.str();
  • 顺便说一句,wstring 是一个可怕的变量名称,因为它与标准库类型 std::wstring 相同。
  • @Galik OP 确实说:“wstring 是字符串流
  • @GhasemRamezani 是否存在std::copy 的重载,它返回一个wchar_t * 字符串,稍后可以由free 释放?

标签: c++ linux windows widechar wchar


【解决方案1】:

标准的跨平台等效项是使用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'\0';
...
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'\0';
...
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() 会返回一个 std::wstring 开头,所以您最好还是坚持使用 std::wstring 而不是使用 wchar_t*

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

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

【讨论】:

  • 好方法。谢谢你。
  • 我个人更喜欢使用std::unique_ptr<wchar_t[]> 而不是自己调用new[]delete[]...您可能需要调用get() 将值传递给某些函数,但这似乎成为我唯一的缺点......
  • @fabian 个人而言,我会在使用std::unique_ptr<wchar_t> 之前使用std::vector<wchar_t>,但单独使用std::wstring 会更好。
【解决方案2】:

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

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

#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-duplicated 字符串,因为它与某些使用一个的 API 进行通信。因此,在我的回答中,我没有夸夸其谈使用 C++ 库功能来解决问题。

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

【讨论】:

    【解决方案3】:

    假设需要将字符串传递给期望为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() 中。

    【讨论】:

    • 这对你有用吗?我不认为sizeof 可以应用于不带括号的类型名称:它是sizeof exprsizeof (type)expr 可以有括号,但(type) 不能省略。
    猜你喜欢
    • 2018-08-31
    • 2014-12-05
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多