将std :: wstring转换为cstring是否安全?

3

需要澄清的是,我不是过度担心数据丢失问题,因为这是用于记录应用程序内操作的日志,我使用wstring作为主要的数据类型。由于我目前使用的框架(默认情况下为std :: string的OpenFrameworks日志记录),所以我对此感到满意。

以下是当前转换示例:

//ofLog.h--patch | `message` is a `std::ostringstream`
    ofLog& operator<<(const std::wstring& value){
        message << value.c_str() << padding;
        return *this;
    }

通过使用这个特定的重载,我可以在冗长的日志中省去很多麻烦,并且不用太担心是否有第三方std :: strings(例如OSC(char)库与JSON(wchar)库)。
我相对较新于C ++,之前一直生活在Java / JavaScript世界中,我想知道这里是否存在除了潜在的数据丢失之外的风险。是否有平台无关的解决方案?我已经谷歌了几个小时,我想要一个“安全”的解决方案,不会在以后给我带来麻烦。
基本上,我的解决方案似乎可行,但我想知道这样做可能存在的潜在问题。
谢谢!(openframeworks标签只是为了帮助我们解决问题)
编辑:如果有人需要这个OpenFrameworks,下面的内容似乎适合我:
/*
ofLog.h
*/
        /// \brief Overload the wstring operator so that this actually works for 
        /// data of that format
        ///
        ofLog& operator<<(const std::wstring& value){
            std::string cvalue;
            std::transform(value.begin(), value.end(), 
                std::back_insert_iterator<std::string>(cvalue),
                [](wchar_t wide) 
                {
                    return static_cast<char>(wide > 127 ? '?' : wide);
                });

            message << cvalue << padding;
            return *this;
        }

        /// \brief Overloaded to support wchar_t * types
        ///
        /// 
        ofLog& operator<<(const wchar_t* value)
        {
            std::wstring wstr(value);
            std::string cvalue;
            std::transform(wstr.begin(), wstr.end(),
                std::back_insert_iterator<std::string>(cvalue),
                [](wchar_t wide)
            {
                return static_cast<char>(wide > 127 ? '?' : wide);
            });

            message << cvalue << padding;
            return *this;
        }
//END ofLog.h

你是否期望你的 wstring 主要由 US-ASCII 内容组成? - Sam Varshavchik
是的,我怀疑对于关键信息,它几乎总是ASCII。 - Daniel B. Chapman
对于std::wstring::c_str(),它返回const wchar_t;然而,std::ostringstream没有以const wchar_t为参数的operator<<重载;它可能选择operator<<(void*),但这可能不是您想要的。 - Kingsley Chen
1个回答

4
显示的代码将无法正常工作。std::wstring的c_str()方法返回一个const wchar_t *。将其传递给std::ostringstream的operator<<将选择接受const void*参数的operator<<重载,这将不会产生任何有用的结果。
您表示期望您的std::wstring主要由US-ASCII字符组成。如果是这样,最简单的方法是粗暴地将std::wstring转换为std::string,以以下方式替换所有非ASCII字符为问号(或选择您喜欢的标点符号):
std::string cvalue;

std::transform(value.begin(), value.end(),
               std::back_insert_iterator<std::string>(cvalue),
               [](wchar_t wchar)
               {
                     return static_cast<char>(wchar > 127 ? '?':wchar);
               });

继续操作,将普通的std::string转化为您的message

如果您预计您的宽字符串主要由US-ASCII内容组成,则这将是一个快速的技巧来完成工作。否则,您需要使用本地化库来使用当前系统语言环境正确地将宽字符串转换为窄字符字符串。这需要相当多的工作...


谢谢Sam,我能否在boost库或其他常用库中找到转换作为参考点?与此同时,“hack”对于这个项目来说似乎是可以的。 - Daniel B. Chapman
如果你的实现使用Unicode作为宽字符,并且你的本地字符集是非常合理的UTF-8,我想推荐一下我的Unicode库 - Sam Varshavchik
我认为转换为UTF-8比丢弃高值更好。 - phuclv
谢谢,这非常有帮助。理想情况下,我可能会尝试默认使用wchar支持来修补OpenFrameworks日志,并转换另一个方向(这应该更安全),但现在这将让我度过难关。 - Daniel B. Chapman

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