You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用wstring_convert实现string与u16string互转方案

解决C++17中std::string与std::u16string/std::wstring的互转问题(无wstring_convert)

Windows平台:使用系统原生API

你之前尝试MultiByteToWideChar失败,大概率是参数配置或缓冲区处理有误,以下是正确的UTF-8与UTF-16(对应std::u16string/std::wstring)互转实现:

UTF-8转std::u16string

#include <windows.h>
#include <string>

std::u16string utf8_to_u16(const char* utf8_str) {
    if (!utf8_str) return {};

    // 获取所需缓冲区大小(包含终止符)
    int buf_len = MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, nullptr, 0);
    if (buf_len <= 0) return {};

    // 分配wstring缓冲区(Windows下wchar_t为16位,与char16_t兼容)
    std::wstring temp_buf(buf_len, L'\0');
    MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, temp_buf.data(), buf_len);

    // 转换为u16string,剔除末尾的终止符
    return std::u16string(reinterpret_cast<const char16_t*>(temp_buf.c_str()), buf_len - 1);
}

std::u16string转UTF-8

std::string u16_to_utf8(const char16_t* u16_str) {
    if (!u16_str) return {};

    // 获取所需缓冲区大小(包含终止符)
    int buf_len = WideCharToMultiByte(CP_UTF8, 0, reinterpret_cast<const wchar_t*>(u16_str), -1, nullptr, 0, nullptr, nullptr);
    if (buf_len <= 0) return {};

    std::string utf8_buf(buf_len, '\0');
    WideCharToMultiByte(CP_UTF8, 0, reinterpret_cast<const wchar_t*>(u16_str), -1, utf8_buf.data(), buf_len, nullptr, nullptr);

    // 剔除末尾的终止符
    return utf8_buf.substr(0, buf_len - 1);
}

std::wstring与std::u16string互转(Windows专属)

Windows下std::wstring本质是UTF-16编码,可直接通过类型转换实现互转:

// wstring转u16string
std::u16string wstring_to_u16(const std::wstring& ws) {
    return std::u16string(reinterpret_cast<const char16_t*>(ws.c_str()), ws.size());
}

// u16string转wstring
std::wstring u16_to_wstring(const std::u16string& u16s) {
    return std::wstring(reinterpret_cast<const wchar_t*>(u16s.c_str()), u16s.size());
}

跨平台方案:纯标准C++实现转换

如果你的模块需要跨Windows/Linux/macOS运行,可使用纯标准C++实现UTF-8与UTF-16的互转,无需依赖任何系统API或第三方库:

UTF-8转std::u16string

#include <string>
#include <cstdint>

std::u16string utf8_to_u16(const char* utf8_str) {
    std::u16string result;
    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(utf8_str);

    while (*ptr) {
        uint32_t codepoint = 0;
        // 解析UTF-8字节序列
        if ((*ptr & 0x80) == 0) {
            codepoint = *ptr++;
        } else if ((*ptr & 0xE0) == 0xC0) {
            codepoint = (*ptr++ & 0x1F) << 6;
            codepoint |= (*ptr++ & 0x3F);
        } else if ((*ptr & 0xF0) == 0xE0) {
            codepoint = (*ptr++ & 0x0F) << 12;
            codepoint |= (*ptr++ & 0x3F) << 6;
            codepoint |= (*ptr++ & 0x3F);
        } else if ((*ptr & 0xF8) == 0xF0) {
            codepoint = (*ptr++ & 0x07) << 18;
            codepoint |= (*ptr++ & 0x3F) << 12;
            codepoint |= (*ptr++ & 0x3F) << 6;
            codepoint |= (*ptr++ & 0x3F);
        } else {
            // 无效UTF-8序列,跳过当前字节
            ++ptr;
            continue;
        }

        // 处理UTF-16代理对(针对U+10000及以上的码点)
        if (codepoint <= 0xFFFF) {
            result.push_back(static_cast<char16_t>(codepoint));
        } else {
            codepoint -= 0x10000;
            result.push_back(static_cast<char16_t>((codepoint >> 10) + 0xD800));
            result.push_back(static_cast<char16_t>((codepoint & 0x3FF) + 0xDC00));
        }
    }
    return result;
}

std::u16string转UTF-8

std::string u16_to_utf8(const char16_t* u16_str) {
    std::string result;
    const char16_t* ptr = u16_str;

    while (*ptr) {
        uint32_t codepoint = 0;
        // 解析UTF-16代理对
        if ((*ptr & 0xFC00) == 0xD800) {
            if (!*(ptr + 1)) break; // 不完整代理对,终止转换
            codepoint = ((static_cast<uint32_t>(*ptr++) & 0x3FF) << 10) | (static_cast<uint32_t>(*ptr++) & 0x3FF);
            codepoint += 0x10000;
        } else {
            codepoint = *ptr++;
        }

        // 编码为UTF-8字节序列
        if (codepoint <= 0x7F) {
            result.push_back(static_cast<char>(codepoint));
        } else if (codepoint <= 0x7FF) {
            result.push_back(static_cast<char>((codepoint >> 6) | 0xC0));
            result.push_back(static_cast<char>((codepoint & 0x3F) | 0x80));
        } else if (codepoint <= 0xFFFF) {
            result.push_back(static_cast<char>((codepoint >> 12) | 0xE0));
            result.push_back(static_cast<char>(((codepoint >> 6) & 0x3F) | 0x80));
            result.push_back(static_cast<char>((codepoint & 0x3F) | 0x80));
        } else if (codepoint <= 0x10FFFF) {
            result.push_back(static_cast<char>((codepoint >> 18) | 0xF0));
            result.push_back(static_cast<char>(((codepoint >> 12) & 0x3F) | 0x80));
            result.push_back(static_cast<char>(((codepoint >> 6) & 0x3F) | 0x80));
            result.push_back(static_cast<char>((codepoint & 0x3F) | 0x80));
        }
    }
    return result;
}

以上两种方案都完全避开了已废弃的wstring_convert,可根据你的平台需求选择使用。

内容的提问来源于stack exchange,提问作者Markstar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 20:36:11