我编写了一个将wstring转换为字符串的函数。如果删除代码setlocale(LC_CTYPE,“”),程序将出错。我参考cplusplus阅读文档。
包含C语言环境名称的C字符串。这些是系统特定的 但至少必须存在以下两个语言环境:
“ C”最小的“ C”语言环境
“”环境的默认语言环境如果此参数的值为NULL,则该函数不执行任何操作 更改为当前语言环境,但当前语言环境的名称为 仍由该函数返回。
我的代码在这里,来自cplusplus.com的源代码(我添加了一些汉字):
/* wcstombs example */
#include <stdio.h> /* printf */
#include <stdlib.h> /* wcstombs, wchar_t(C) */
#include <locale.h> /* setlocale */
int main()
{
setlocale(LC_CTYPE, "");
const wchar_t str[] = L"中国、wcstombs example";
char buffer[64];
int ret;
printf ("wchar_t string: %ls \n",str);
ret = wcstombs ( buffer, str, sizeof(buffer) );
if (ret==64)
buffer[63]='\0';
if (ret)
printf ("length:%d,multibyte string: %s \n",ret,buffer);
return 0;
}
如果删除代码setlocale(LC_CTYPE,“”),则程序无法按预期运行。 我的问题是:“如果我在不同的计算机上运行,程序会有所不同吗?如文档所说,如果语言环境为”,函数不会对当前语言环境进行任何更改,但仍会返回当前语言环境的名称通过功能。” 因为不同机器上的当前语言环境可能不同?
这是我的c ++版本的将wstring转换为string的c ++版本,而string到wstring不需要函数setlocale,并且程序运行良好:
/*
string converts to wstring
*/
std::wstring s2ws(const std::string& src)
{
std::wstring res = L"";
size_t const wcs_len = mbstowcs(NULL, src.c_str(), 0);
std::vector<wchar_t> buffer(wcs_len + 1);
mbstowcs(&buffer[0], src.c_str(), src.size());
res.assign(buffer.begin(), buffer.end() - 1);
return res;
}
/*
wstring converts to string
*/
std::string ws2s(const std::wstring & src)
{
setlocale(LC_CTYPE, "");
std::string res = "";
size_t const mbs_len = wcstombs(NULL, src.c_str(), 0);
std::vector<char> buffer(mbs_len + 1);
wcstombs(&buffer[0], src.c_str(), buffer.size());
res.assign(buffer.begin(), buffer.end() - 1);
return res;
}
答案 0 :(得分:1)
如果setlocale的第二个参数为NULL,则除了返回当前语言环境外,它不会做任何其他事情。但是你没有那样做。您正在向其发送一个完全由单个nil字节(也称为""
)组成的字符串。我的setlocale手册页说
如果语言环境是一个空字符串“”,则根据环境变量设置应修改的语言环境的每个部分。详细信息取决于实现。
所以这对您来说是将语言环境设置为用户指定的内容或系统默认值。
完全不运行setlocale可能会使当前语言环境在系统上处于未初始化状态或为NULL,这就是为什么您的程序在没有该设置的情况下会失败。
另外两页有关您正在使用的内容的手册页
mbstowcs()的行为取决于当前语言环境的LC_CTYPE类别。
wcstombs()的行为取决于当前语言环境的LC_CTYPE类别。
如果您根本没有设置语言环境,那么这些例程大概就是失败的原因。
我想您可能不需要在每次调用这些例程时都运行setlocale语句,但是您需要确保在运行它们之前至少运行一次。
就根据当前语言环境发生的变化而言,我相信这将是将多字节字符串转换为宽字符的正确方式,反之亦然。我认为由于这些差异,这些例程的手册页含糊不清。就个人而言,我希望它设置一些示例,例如“如果当前语言环境为C
,则多字节字符串为ASCII字符”。我猜想至少还有一个将其解释为UTF-8,但我对不同的语言环境了解不足,无法确切地说出是哪个语言环境。可能至少在一个语言环境中,多字节字符串碰巧是每个字符编码另外两个字节,但是C和C ++仍会将其视为字节。
编辑:考虑到这一点,考虑到您添加到示例代码中的字符,可以明确地声明使用不支持中文字符的语言环境将导致最终的printf报告长度为-1,包括默认的C语言环境。在这种情况下,缓冲区的内容没有由标准明确指定-至少,我的阅读表明,缓冲区的值可能是所有字符,直到但不包括未能转换的字符。尽管C ++文档和C文档都没有说明关于无法转换的字符会发生什么情况。我没有为官方标准付费,但是我有最新免费版本的副本。 C ++ 17遵循C17。 C17也拒绝评论此功能的这一方面。对于wcsrtombs,它明确指出转换状态未指定。但是,在wcstombs_s上,C17状态为
如果在不转换宽宽度字符的情况下停止转换并且dst不是空指针,则将空字符存储在dst指向的数组中,紧跟已存储的任何多字节字符之后。
在我自己上面的OP提供的代码的实验中,看来Fedora 28上的wcstombs实现只是避免对缓冲区进行任何进一步的更改。这似乎向我表明,如果代码的确切行为对于这种情况很重要,则可以改用wcstombs_s。但是至少,您只需要检查返回的长度是否为-1,如果是,则报告错误,而不是假定转换有效。