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

在C++中能否定义Shift-JIS字符串字面量?求更简便实现方案

问题

我正在编写一个涉及比较Shift-JIS编码字符串的程序,仅需与几个固定值进行比对,希望将这些值编码为字符串常量/字面量。我已经通过iconv或MultiByteToWideChar/WideCharToMultiByte函数实现了自定义字面量,但想了解是否存在其他实现方法,或更简便的自定义字面量定义方式。

背景信息

  • 程序仅针对Windows平台编译
  • 使用Mingw64交叉编译器从Linux环境构建
  • 待比对的字符串均为16字节固定长度
  • 可使用C17特性,但无法使用C20特性

当前实现代码

auto operator "" _sjs(const char* in, std::size_t len)
{
#ifdef HAS_ICONV
    auto t = iconv_open("SHIFT-JIS", "UTF-8");
    // max length of BS header name + 1 for terminator
    char output[17] = "";
    memset(output, ' ', 16);
    size_t outLeft = 16;
    char* tmpOut = output;
    iconv(t, &in, &len, &tmpOut, &outLeft);
    iconv_close(t);
    return std::string{output};
#else
    wchar_t output[34];
    memset(output, 0, 34);
    MultiByteToWideChar(CP_UTF8, 0, in, -1, output, len);
    
    char output2[17] = "";
    memset(output2, ' ', 16);
    WideCharToMultiByte(932, 0, output, -1, output2, len*2, NULL, NULL);
    return std::string{output2};
#endif
}
可行优化方案

1. 预编码为二进制字面量(最简便直接)

既然待比对的是固定16字节的Shift-JIS字符串,完全可以提前把这些字符串转换成Shift-JIS字节序列,直接用二进制字面量定义成std::array<char,16>或者字符数组常量,不需要运行时转换:

比如,先通过Linux工具生成目标字符串的Shift-JIS十六进制字节(命令示例:echo "目标字符串" | iconv -f UTF-8 -t SHIFT-JIS | xxd -i),再定义常量:

constexpr std::array<char,16> SJIS_TARGET = {
    0x83,0x65,0x83,0x58,0x83,0x67,0x82,0xB7,
    0x82,0xEA,0x82,0xC5,0x20,0x20,0x20,0x20 // 补空格到16字节
};

这种方式在编译期就完成编码转换,运行时直接用常量比对,无性能开销,也省去了自定义字面量的运行时转换逻辑。

2. 简化自定义字面量的实现逻辑

如果坚持要用自定义字面量,可以优化现有代码的冗余和错误处理:

  • 统一空格填充逻辑,避免重复代码
  • 增加转换失败的错误检查,避免非法结果
  • 明确返回固定16字节的字符串

优化后的代码示例:

#include <string>
#include <cstring>
#include <stdexcept>

std::string operator "" _sjs(const char* in, std::size_t len)
{
    char output[17] = {0};
    std::memset(output, ' ', 16); // 统一先填充空格到16字节

#ifdef HAS_ICONV
    iconv_t cd = iconv_open("SHIFT-JIS", "UTF-8");
    if (cd == (iconv_t)-1) {
        throw std::runtime_error("Failed to initialize iconv");
    }

    size_t in_left = len;
    char* in_ptr = const_cast<char*>(in);
    size_t out_left = 16;
    char* out_ptr = output;

    if (iconv(cd, &in_ptr, &in_left, &out_ptr, &out_left) == (size_t)-1) {
        iconv_close(cd);
        throw std::runtime_error("Shift-JIS conversion failed");
    }
    iconv_close(cd);
#else
    wchar_t wide_buf[34] = {0};
    int wide_len = MultiByteToWideChar(CP_UTF8, 0, in, static_cast<int>(len), wide_buf, 33);
    if (wide_len == 0) {
        throw std::runtime_error("UTF-8 to wide char conversion failed");
    }

    int sjis_len = WideCharToMultiByte(932, 0, wide_buf, wide_len, output, 16, nullptr, nullptr);
    if (sjis_len == 0) {
        throw std::runtime_error("Wide char to Shift-JIS conversion failed");
    }
#endif

    return std::string(output, 16); // 确保返回固定16字节长度
}

3. 利用Mingw64的编码扩展特性

Mingw64支持通过编译器属性直接指定字符串字面量的编码,适合字符串数量少的场景:

// 需确保源代码文件编码与指定编码匹配,或编译器能正确识别
const char* target_sjis __attribute__((encoding("Shift-JIS"))) = "目标文字列    "; // 手动补空格到16字节

注意这种方式依赖编译器扩展,移植性稍差,但对于固定平台的简单场景来说非常简便。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 20:40:25