将 wstring 转换为 string 的古代代码中的可怕警告
Scary warnings in ancient code converting wstring to string
旧方法包含如下代码(匿名):
std::wstring wstr = ...;
std::string str(wstr.begin(), wstr.end());
以前这一切都在没有警告的情况下编译,但当我们更新到 C++17 和 VS2019 (v142) 并整理项目设置时,它现在会给出这些可怕的大警告:
C:\Program Files (x86)\Microsoft Visual Studio19\Professional\VC\Tools\MSVC.28.29333\include\xstring(2468,23): warning C4244: 'argument': conversion from 'wchar_t' to 'const _Elem', possible loss of data
with
[
_Elem=char
]
C:\Program Files (x86)\Microsoft Visual Studio19\Professional\VC\Tools\MSVC.28.29333\include\xstring(2479): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(_Iter,const _Iter,std::input_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio19\Professional\VC\Tools\MSVC.28.29333\include\xstring(2479): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(_Iter,const _Iter,std::input_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio19\Professional\VC\Tools\MSVC.28.29333\include\xstring(2459): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(const _Iter,const _Iter,std::forward_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio19\Professional\VC\Tools\MSVC.28.29333\include\xstring(2459): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(const _Iter,const _Iter,std::forward_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
message : see reference to function template instantiation '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 &)' being compiled
with
[
_Elem=wchar_t,
_Iter=std::_String_iterator<std::_String_val<std::_Simple_types<wchar_t>>>,
_Alloc=std::allocator<char>
]
message : see reference to function template instantiation '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 &)' being compiled
with
[
_Elem=wchar_t,
_Iter=std::_String_iterator<std::_String_val<std::_Simple_types<wchar_t>>>,
_Alloc=std::allocator<char>
]
我很确定这段代码早于我们的代码库中使用 UNICODE - 它 似乎 可以工作,但我真的不明白警告或我应该怎么做它。
我发现了这个问题:UTF8 to/from wide char conversion in STL 但是这个简洁的解决方案有评论说它在 C++17 中已被弃用!为什么这段代码首先混合了 string 和 wstring 有点神秘,有没有简单的解决方案?还是这种情况“如果它有效就离开它?!”
问题是您正在从 16 位字符串转换为 8 位字符串。由于 16 位比 8 位包含更多数据,因此数据将丢失。如果要在 UTF-16 和 UTF-8 之间进行转换,则需要使用转换库正确地进行转换。
C++ 确实以以下形式提供转换库:codecvt(在 C++17 中已弃用,但仍然存在一段时间)。
如果您确定字符串仅包含 ASCII,则可以取消警告。
详情见https://en.cppreference.com/w/cpp/locale/codecvt_utf8_utf16
警告本身就很清楚。
warning C4244: 'argument': conversion from 'wchar_t' to 'const _Elem',
possible loss of data
这意味着,这一行 std::string str(wstr.begin(), wstr.end())
涉及从 wchar_t
到更窄的数据类型 const _Elem
a.k.a char
的类型转换。由于任何缩小转换都可能导致数据丢失,因此出现警告。
考虑如下示例:
#include <cstddef>
#include <iostream>
#include <string>
int main() {
std::wstring ws{};
auto c = (wchar_t)0x41'42'43'44; // A'B'C'D in ASCII
for (int i = 0; i < 3; ++i)
ws.push_back(c);
std::string str{ws.begin(), ws.end()};
std::cout << str.c_str() << std::endl;
}
上面的代码 运行 并打印 DDD
.
在 64 位机器上,str
的构造函数一次移动 4 个字节来读取 wchar_t
。但是,字符串类型只能接受元素作为 char
==> 构造函数必须执行从 wchar_t
到 char
的缩小转换,这会导致丢失 3 个字节 A B C
每个 wchar_t
个元素。
旧方法包含如下代码(匿名):
std::wstring wstr = ...;
std::string str(wstr.begin(), wstr.end());
以前这一切都在没有警告的情况下编译,但当我们更新到 C++17 和 VS2019 (v142) 并整理项目设置时,它现在会给出这些可怕的大警告:
C:\Program Files (x86)\Microsoft Visual Studio19\Professional\VC\Tools\MSVC.28.29333\include\xstring(2468,23): warning C4244: 'argument': conversion from 'wchar_t' to 'const _Elem', possible loss of data
with
[
_Elem=char
]
C:\Program Files (x86)\Microsoft Visual Studio19\Professional\VC\Tools\MSVC.28.29333\include\xstring(2479): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(_Iter,const _Iter,std::input_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio19\Professional\VC\Tools\MSVC.28.29333\include\xstring(2479): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(_Iter,const _Iter,std::input_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio19\Professional\VC\Tools\MSVC.28.29333\include\xstring(2459): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(const _Iter,const _Iter,std::forward_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio19\Professional\VC\Tools\MSVC.28.29333\include\xstring(2459): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(const _Iter,const _Iter,std::forward_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
message : see reference to function template instantiation '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 &)' being compiled
with
[
_Elem=wchar_t,
_Iter=std::_String_iterator<std::_String_val<std::_Simple_types<wchar_t>>>,
_Alloc=std::allocator<char>
]
message : see reference to function template instantiation '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 &)' being compiled
with
[
_Elem=wchar_t,
_Iter=std::_String_iterator<std::_String_val<std::_Simple_types<wchar_t>>>,
_Alloc=std::allocator<char>
]
我很确定这段代码早于我们的代码库中使用 UNICODE - 它 似乎 可以工作,但我真的不明白警告或我应该怎么做它。
我发现了这个问题:UTF8 to/from wide char conversion in STL 但是这个简洁的解决方案有评论说它在 C++17 中已被弃用!为什么这段代码首先混合了 string 和 wstring 有点神秘,有没有简单的解决方案?还是这种情况“如果它有效就离开它?!”
问题是您正在从 16 位字符串转换为 8 位字符串。由于 16 位比 8 位包含更多数据,因此数据将丢失。如果要在 UTF-16 和 UTF-8 之间进行转换,则需要使用转换库正确地进行转换。
C++ 确实以以下形式提供转换库:codecvt(在 C++17 中已弃用,但仍然存在一段时间)。
如果您确定字符串仅包含 ASCII,则可以取消警告。
详情见https://en.cppreference.com/w/cpp/locale/codecvt_utf8_utf16
警告本身就很清楚。
warning C4244: 'argument': conversion from 'wchar_t' to 'const _Elem', possible loss of data
这意味着,这一行 std::string str(wstr.begin(), wstr.end())
涉及从 wchar_t
到更窄的数据类型 const _Elem
a.k.a char
的类型转换。由于任何缩小转换都可能导致数据丢失,因此出现警告。
考虑如下示例:
#include <cstddef>
#include <iostream>
#include <string>
int main() {
std::wstring ws{};
auto c = (wchar_t)0x41'42'43'44; // A'B'C'D in ASCII
for (int i = 0; i < 3; ++i)
ws.push_back(c);
std::string str{ws.begin(), ws.end()};
std::cout << str.c_str() << std::endl;
}
上面的代码 运行 并打印 DDD
.
在 64 位机器上,str
的构造函数一次移动 4 个字节来读取 wchar_t
。但是,字符串类型只能接受元素作为 char
==> 构造函数必须执行从 wchar_t
到 char
的缩小转换,这会导致丢失 3 个字节 A B C
每个 wchar_t
个元素。