如何将Platform::String转换为char*?

18

我如何将Platform::String的内容转换为函数期望的基于char*的字符串?我假设WinRT提供了帮助函数,但我找不到它们。

谢谢!


除非您指定目标字符编码,否则无法要求从UTF-16LE进行转换。它是什么? - IInspectable
6个回答

15

以下是一种非常简单的方法在代码中实现此功能,无需担心缓冲区长度。 只有在确保处理的是ASCII字符时才使用此解决方案:

Platform::String^ fooRT = "aoeu";
std::wstring fooW(fooRT->Begin());
std::string fooA(fooW.begin(), fooW.end());
const char* charStr = fooA.c_str();

请记住,在此示例中,char* 存储在栈中,一旦离开作用域就会消失。


3
每个问题都有一个简单、优雅的解决方案,但这种方案往往是错误的,就像这个例子一样。如果字符超出 ASCII 字符范围,它们将被随机地替换成不确定的表示形式,具体取决于执行线程的当前状态。不要使用这种解决方案(而且它甚至无法编译)。 - IInspectable
修复了编译器错误。附注:如果您确信只需要处理ASCII字符,则仍然是一种不错的转换方式。 - bas
std::string这一行会生成编译消息,有没有什么方法可以避免这种情况? “参见函数模板实例化 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string<std::_String_iterator<std::_String_val<std::_Simple_types<_Elem>>>,0>(_Iter,_Iter,const _Alloc &)'正在被编译, 其中 [ _Elem=wchar_t, _Iter=std::_String_iterator<std::_String_val<std::_Simple_types<wchar_t>>>, _Alloc=std::allocator<char> ]” - escape-llc

13

Platform::String::Data() 将返回指向字符串内容的 wchar_t const* 指针(类似于 std::wstring::c_str())。Platform::String 表示一个不可变字符串,因此没有访问器来获取 wchar_t*。如果要进行更改,则需要将其内容复制到 std::wstring 中。

没有直接的方法可以获取 char*char const*,因为 Platform::String 使用宽字符(所有 Metro 样式应用程序都是 Unicode 应用程序)。可以使用 WideCharToMultiByte 进行多字节转换。


有没有任何针对 Metro 特定的“间接”方法可以转换为 char*? - djcouchycouch
@JamesMcNellis 如果 String 是不可变的,为什么 String::Begin 返回一个 char16 * 而不是 char16 const*?使用这个指针修改单个字符是否合法? - Praetorian
@Prætorian:文档有误。Begin()End()都返回char16 const*。你可以在<vccorlib.h>中看到它们的定义。你不能修改指向的字符(字符串是引用计数的,如果有其他所有者并且你修改了字符串,那些其他所有者会非常惊讶地发现他们的字符串已经改变)。我会尽力让文档修正。感谢你的提醒。 - James McNellis
4
这并没有回答问题。他问如何将Platform::String转换为char*,有方法可以做到这一点。WideCharToMultiByte函数可以实现,但对该函数不熟悉的人可能不知道如何使用它。 - Eric
如果使用真正的HSTRING,则HString :: GetRawBuffer还将使用WRL和WindowsGetStringRawBuffer来返回wchar_t *。 - Dwayne Robinson
显示剩余2条评论

8

不应该将宽字符转换为char,否则会破坏使用超过一个字节的语言,例如中文。以下是正确的方法。

#include <cvt/wstring>
#include <codecvt>

Platform::String^ fooRT = "foo";
stdext::cvt::wstring_convert<std::codecvt_utf8<wchar_t>> convert;
std::string stringUtf8 = convert.to_bytes(fooRT->Data());
const char* rawCstring = stringUtf8.c_str();

或者使用不带stdext的一行代码: char* raw = std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(fooRT->Data()).c_str(); - Quest
2
但是使用@Quest的方法,如果直接使用,则“raw”变量将指向已释放的内存(临时对象在表达式求值后消失)。最好使用std :: string utf8 = std :: wstring_convert <std :: codecvt_utf8 <wchar_t>>().to_bytes(fooRT-> Data()),除非您确定自己知道自己在做什么。 - Emil Styrke
这个解决方案没有生成任何编译器消息! - escape-llc

1
一种使用 wcstombs 的解决方案:

Platform::String^ platform_string = p_e->Uri->AbsoluteUri;
const wchar_t* wide_chars =  platform_string->Data();
char chars[512];
wcstombs(chars, wide_chars, 512);

wcstombs generates this warning 'wcstombs': This function or variable may be unsafe. Consider using wcstombs_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. - escape-llc
我猜警告已经解释了一切,使用wcstombs_s会更安全,但需要付出一些额外的冗长。 - Sistr
你的评论并没有提供有用的信息,因为我和其他来到这里的人并不都是C++/Windows专家(我试图做一些C#互操作),我只是转述编译器在尝试此页面上的答案时告诉我的内容。也许你可以更新你的答案并提供更多价值? - escape-llc

1

有一个名为String::Data的方法,返回const char16*,这是原始的Unicode字符串。

从Unicode转换为ASCII或其他格式,即从char16*char*,是另一回事。您可能不需要它,因为大多数方法现在都有它们的wchar版本。


2
唉,我并不生活在一个wchar的世界中。我正在处理的大部分代码都是旧代码,期望使用8位字符字符串。 :) - djcouchycouch

0

解决方案1:

#include <cvt/wstring>
#include <codecvt>

Platform::String^ tTextRT = "TestText";
stdext::cvt::wstring_convert<std::codecvt_utf8<wchar_t>> convert;
std::string stringUtf8 = convert.to_bytes(tTextRT->Data());
const char* rawCstring = stringUtf8.c_str();

但是这个解决方案会产生错误。
引用: 错误 C4996 'stdext::cvt':警告 STL4044:stdext::cvt 命名空间的内容是非标准扩展,并将在将来被移除。可以使用 MultiByteToWideChar() 和 WideCharToMultiByte() 函数代替。您可以定义 _SILENCE_STDEXT_CVT_DEPRECATION_WARNING 或 _SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS 来抑制此警告。
解决方案 2:
Platform::String^ testText = "Test Text";
std::wstring tTextW(testText->Begin());
std::string tTextA(tTextW.begin(), tTextW.end());
const char* charStr = tTextA.c_str();

但是这个解决方案还有另一个问题:
任何超出ASCII字符范围的字符都会被销毁为一个随机的表示,这取决于执行线程的当前状态。
可行的解决方案:
#include <cvt/wstring>
#include <stringapiset.h>

Platform::String^ testText = "foo";
const wchar_t* pWStr = testText->Data();
int bufferSize = WideCharToMultiByte(CP_UTF8, 0, pWStr, -1, NULL, 0, NULL, NULL);
char* stringUtf8 = new char[bufferSize + 1];
memset(stringUtf8, 0, bufferSize + 1);
if (0 == WideCharToMultiByte(CP_UTF8, 0, pWStr, -1, stringUtf8, bufferSize, NULL, NULL))
{
    throw std::exception("Can't convert string to Unicode");
}
const char* rawCstring = std::string(stringUtf8).c_str();
delete[] stringUtf8;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接