【问题标题】:How to convert char* to wchar_t*?如何将 char* 转换为 wchar_t*?
【发布时间】:2018-01-07 12:59:55
【问题描述】:

我尝试过实现这样的功能,但不幸的是它不起作用:

const wchar_t *GetWC(const char *c)
{
    const size_t cSize = strlen(c)+1;
    wchar_t wc[cSize];
    mbstowcs (wc, c, cSize);

    return wc;
}

我的主要目标是能够将普通字符字符串集成到 Unicode 应用程序中。非常感谢你们提供的任何建议。

【问题讨论】:

  • 您给出的代码不起作用怎么办?请描述您遇到的问题。我可以猜到它是什么,但如果你能找出问题,它会有所帮助。
  • 请注意strlen() 是错误的,您需要使用mbslen() 之类的东西来代替[使用mbstowcs(NULL, ...) 完成]。 UTF-8 没有相同数量的字符。 MS-Windows 下的 wchar_t 也使用 UTF-16,这增加了在测量字符串长度时要考虑的另一件有趣的事情。

标签: c++ winapi unicode mingw type-conversion


【解决方案1】:

在您的示例中,wc 是一个局部变量,将在函数调用结束时释放。这会将您置于未定义的行为领域。

简单的解决方法是这样的:

const wchar_t *GetWC(const char *c)
{
    const size_t cSize = strlen(c)+1;
    wchar_t* wc = new wchar_t[cSize];
    mbstowcs (wc, c, cSize);

    return wc;
}

请注意,调用代码将不得不释放此内存,否则会发生内存泄漏。

【讨论】:

  • 教新手不好的做法,比如使用原始new,这可不好。你至少应该提到这意味着什么。和替代品。
  • @Alexis Wilke - 需要解释更多吗?
  • strlen() 在 mbstring 上不返回 wstring 的大小。您需要执行cSize = mbstowcs(NULL, c, 0) + 1; 才能获得正确的尺寸。
  • @Alexis Wilke - 为什么你认为c 是一个mbstring?
  • 否则为什么要使用mbstowcs()?!如果您的语言环境发生变化,多个字节可能代表单个 UTF-16 字符,而其他序列可能代表 UTF-16 中的两个条目(某些中文等使用每个字符 4 个字节进行编码。)
【解决方案2】:

使用 std::wstring 而不是 C99 可变长度数组。当前标准保证std::basic_string 的连续缓冲区。例如,

std::wstring wc( cSize, L'#' );
mbstowcs( &wc[0], c, cSize );

C++ 不支持 C99 可变长度数组,因此如果您将代码编译为纯 C++,它甚至无法编译。

通过该更改,您的函数返回类型也应该是std::wstring

记得在main中设置相关的语言环境。

例如,setlocale( LC_ALL, "" )

【讨论】:

  • 你不需要C++11来保证字符串缓冲区是连续存储的吗?
  • 如答案所述,当前标准保证,是的。该提案在 2005 年 4 月的利勒哈默尔会议上获得通过。
  • 我添加了您的代码 sn-p 并且该功能现在似乎可以工作了!虽然我不必返回wstring,因为我只是使用了c_str() 成员函数并返回了它。看来我也不需要调用setlocale,因为默认值现在似乎就足够了。
  • @AutoBotAM:返回wstring.c_str(),你将再次遇到同样的问题。当函数退出时,所有局部变量都被销毁,包括wstring 类型的变量。 c_str() 的返回值仅在其对应的 wstring 对象的生命周期内有效。尽管您的代码可能看起来运行正常,但它正在访问已释放的内存,并且有一天它会因当时对您而言并不明显的原因而神秘地失败。
  • 问题明确指出目标类型是wchar_t,而不是wstring。为什么将此题外话标记为解决方案?
【解决方案3】:
const char* text_char = "example of mbstowcs";
size_t length = strlen(text_char );

“mbstowcs”使用示例

std::wstring text_wchar(length, L'#');

//#pragma warning (disable : 4996)
// Or add to the preprocessor: _CRT_SECURE_NO_WARNINGS
mbstowcs(&text_wchar[0], text_char , length);

使用示例“mbstowcs_s”

微软建议使用“mbstowcs_s”而不是“mbstowcs”。

链接:

Mbstowcs example

mbstowcs_s, _mbstowcs_s_l

wchar_t text_wchar[30];

mbstowcs_s(&length, text_wchar, text_char, length);

【讨论】:

  • 上面对 mbstowcs_s 的调用缺少 arg?
【解决方案4】:

您正在返回分配在堆栈上的局部变量的地址。当您的函数返回时,所有局部变量(例如 wc)的存储空间都将被释放,并会立即被其他东西覆盖。

要解决此问题,您可以将缓冲区的大小传递给GetWC,但是您将获得与mbstowcs 本身几乎相同的接口。或者,您可以在 GetWC 内分配一个新缓冲区并返回一个指向该缓冲区的指针,让调用者自行释放缓冲区。

【讨论】:

  • C++ 的方式是不做原始的new(一般来说)。例如。 std::wstring 是这里的自然结果类型。至少当你没有更好的东西时。此外,由于代码被视为 C++,他没有返回任何内容。代码不会编译为 C++。
【解决方案5】:

您的问题与编码无关,只是了解基本 C++ 的简单问题。您正在从您的函数返回一个指向 局部变量 的指针,当任何人都可以使用它时,该指针将超出范围,从而创建 未定义的行为(即编程错误)。

遵循这条黄金法则:“如果您使用裸字符指针,那么您做错了。(除非您没有这样做。)”

我有 previously posted 一些代码在 C++ std::stringstd::wstring 对象中进行转换和通信输入和输出。

【讨论】:

    【解决方案6】:

    我做了这样的事情。前 2 个零是因为我不知道这个命令想要我提供什么样的 ascii 类型的东西。我的总体感觉是创建一个临时字符数组。传入宽字符数组。繁荣。有用。 +1 确保空终止字符位于正确的位置。

    char tempFilePath[MAX_PATH] = "I want to convert this to wide chars";
    
    int len = strlen(tempFilePath);
    
    // Converts the path to wide characters
        int needed = MultiByteToWideChar(0, 0, tempFilePath, len + 1, strDestPath, len + 1);
    

    【讨论】:

      【解决方案7】:

      Andrew Shepherd 的回答。

      Andrew Shepherd 的回答对我有好处,我添加了一些修复方法: 1、去掉结尾字符L'\0',不然会麻烦。 2、使用mbstowcs_s

      std::wstring wtos(std::string& value){
          const size_t cSize = value.size() + 1;
      
          std::wstring wc;
          wc.resize(cSize);
      
          size_t cSize1;
          mbstowcs_s(&cSize1, (wchar_t*)&wc[0], cSize, value.c_str(), cSize);
      
          wc.pop_back();
      
          return wc;
      }
      

      【讨论】:

        猜你喜欢
        • 2011-03-14
        • 2021-01-29
        • 2011-07-27
        • 1970-01-01
        • 1970-01-01
        • 2011-12-11
        • 2012-06-07
        相关资源
        最近更新 更多