0

旧方法包含如下代码(匿名):

        std::wstring wstr = ...;
        std::string str(wstr.begin(), wstr.end());

以前这一切都在没有警告的情况下编译,但随着我们更新到 C++17 和 VS2019 (v142) 以及整洁的项目设置,它现在给出了这些可怕的警告:

C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.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 Studio\2019\Professional\VC\Tools\MSVC\14.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 Studio\2019\Professional\VC\Tools\MSVC\14.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 Studio\2019\Professional\VC\Tools\MSVC\14.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 Studio\2019\Professional\VC\Tools\MSVC\14.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 有点神秘,有没有简单的解决方案?或者这是一个案例“如果它有效就离开它?!”

4

2 回答 2

1

警告本身就很清楚。

警告 C4244:“参数”:从“wchar_t”转换为“const _Elem”,可能丢失数据

这意味着,这一行std::string str(wstr.begin(), wstr.end())涉及从wchar_t更窄的数据类型const _Elemaka的类型转换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,从而导致A B C每个wchar_t元素丢失 3 个字节。

于 2021-07-13T16:16:50.307 回答
1

问题是您正在从 16 位字符串转换为 8 位字符串。由于 16 位存储的数据多于 8 位,因此数据会丢失。如果您在 UTF-16 和 UTF-8 之间进行转换,则需要使用转换库正确地进行转换。

C++ 确实提供了以下形式的转换库:codecvt(在 C++17 中已弃用,但仍然存在一段时间)。

如果您确定字符串仅包含 ASCII,则可以取消警告。

有关详细信息,请参阅https://en.cppreference.com/w/cpp/locale/codecvt_utf8_utf16

于 2021-07-13T15:04:47.307 回答