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

如何将int转换为宽字符?解析sprintf多字节编码异常问题

关于sprintf用%lc格式化宽字符的编码问题

当我使用sprintf配合%lc格式化大于255的整数时,sprintf会将单个宽字符保存为多个单字节字符。

示例代码如下:

#include <locale.h>
#include <stdio.h>
int main() {
  setlocale(LC_ALL, "");
  char buf[200] = "\0";
  int wide_char = 500; // example
  sprintf(buf, "%lc test", wide_char);
  printf("%s\n", buf);
  printf("%d %d %d\n", (unsigned char)buf[0], (unsigned char)buf[1], (unsigned char)buf[2]);
  return 0;
}

运行结果:

Ǵ test
199 180 32

值为500的宽字符被转换为199和180,对应的二进制格式如下:

1 11110100 // 500
11000111 10110100 // 199和180

我的目标是理解如何将int转换为宽字符,并学会手动将宽字符保存到字符串中(如同处理普通字符那样,比如buf[0] = 97)。我观察到一些规律,但无法理解。更多示例:

10000000 // int = 128
11000010 10000000 // 编码后的宽字符

       1 10000001 // int = 385
11000110 10000001

      10 10000001 // int = 641
11001010 10000001

      11 10000001 // int = 897
11001110 10000001

       1 00000110 // int = 262
11000100 10000110

编码规则解释

你看到的是UTF-8编码的转换逻辑,setlocale(LC_ALL, "")会将程序的locale设置为系统默认编码(通常是UTF-8),sprintf用%lc处理宽字符时,会把你传入的int值(即Unicode码点)转换成UTF-8编码的多字节序列。

针对你示例里的码点范围(128~2047),UTF-8的2字节编码规则如下:

  1. 将码点转为二进制,补前导零凑成11位。比如500的二进制是11110100,凑成11位为001 1110100。
  2. 第一个字节格式为110xxxxx:取11位里的前5位填入xxxxx,即110+00111 → 11000111(对应十进制199)。
  3. 第二个字节格式为10xxxxxx:取11位里剩下的6位填入xxxxxx,即10+110100 → 10110100(对应十进制180)。

所有示例都符合这个逻辑,比如码点128的二进制10000000凑成11位是000 1000000,第一个字节是11000010,第二个字节是10000000,和示例完全匹配。

手动保存宽字符到字符串的方法

如果要手动把Unicode码点(int值)转成UTF-8并存入char数组,直接按上述规则拆分二进制即可:

  1. 判断码点范围,确定需要的字节数(128~2047用2字节)。
  2. 按UTF-8的格式填充每个字节的二进制位。
  3. 将每个字节的二进制转为unsigned char,依次存入数组。

比如手动处理码点500:

char buf[3];
// 第一个字节:0xC7对应二进制11000111
buf[0] = 0xC7;
// 第二个字节:0xB4对应二进制10110100
buf[1] = 0xB4;
// 字符串结束符
buf[2] = '\0';

此时buf中就是UTF-8编码的Ǵ字符。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 15:15:56