編碼背景知識
中文環境常用 GB2312(國標碼,6763 漢字)與 GBK(擴展,含繁體,21003 漢字)編碼。兩者均為雙字節編碼:
- GB2312:高字節 0xB0–0xF7,低字節 0xA0–0xFE
- GBK:高字節 0x81–0xFE,低字節 0x40–0xFE(兼容 GB2312)
全角字符佔 2 字節,半角字符佔 1 字節。全角 ASCII 範圍:0xA3A1 (全角空格) 至 0xA3FE (全角 ~);對應半角 0x20–0x7E。
轉換規則
| 方向 | 條件 | 轉換公式 |
| 全角→半角 (SBC2DBC) | 全角空格 0xA3A1 | 半角空格 0x20 |
| 全角字符 0xA3A2–0xA3FE | 減 0x80 (即 -128) |
| 半角→全角 (DBC2SBC) | 半角空格 0x20 | 全角空格 0xA3A1 |
| 半角字符 0x21–0x7E | 加 0x80 (即 +128) |
完整實現代碼
#include <stdint.h>
/* 全角轉半角:輸入 src,輸出 dst,返回轉換後長度 */
size_t sbc_to_dbc(const char *src, char *dst) {
size_t len = 0;
while (*src) {
uint8_t hi = (uint8_t)*src;
if (hi == 0xA3 && src[1]) { // 可能是全角 ASCII
uint8_t lo = (uint8_t)src[1];
if (lo == 0xA1) { // 全角空格
*dst++ = 0x20;
} else if (lo >= 0xA2 && lo <= 0xFE) { // 全角 ! ~
*dst++ = lo - 0x80;
} else { // 非全角 ASCII,原樣複製
*dst++ = *src++;
continue;
}
src += 2;
} else if (hi >= 0x81) { // 中文字符雙字節
*dst++ = *src++;
*dst++ = *src++;
} else { // 單字節字符(半角或其它)
*dst++ = *src++;
}
len++;
}
*dst = '\0';
return len;
}
/* 半角轉全角 */
size_t dbc_to_sbc(const char *src, char *dst) {
size_t len = 0;
while (*src) {
uint8_t c = (uint8_t)*src;
if (c == 0x20) { // 半角空格
*dst++ = 0xA3; *dst++ = 0xA1;
} else if (c >= 0x21 && c <= 0x7E) { // 半角可見字符
*dst++ = 0xA3; *dst++ = c + 0x80;
} else if (c >= 0x81) { // 中文字符雙字節
*dst++ = *src++;
*dst++ = *src++;
} else { // 控制字符等,原樣複製
*dst++ = *src++;
}
src++;
len++;
}
*dst = '\0';
return len;
}
使用示例
int main() {
char src[] = "Hello World!"; // 全角字符串
char buf[100];
sbc_to_dbc(src, buf);
printf("半角: %s\n", buf); // Hello World!
char src2[] = "Hello World!";
dbc_to_sbc(src2, buf);
printf("全角: %s\n", buf); // Hello World!
return 0;
}
注意事項
- 代碼假設運行環境為 GBK/GB2312 本地編碼(如 Windows 控制台 CP936 或 Linux zh_CN.GBK)。
- UTF-8 環境下全角字符佔 3 字節,需改用 Unicode 碼點判斷(
U+FF01–U+FF5E)。
- 輸出緩衝區需預留足夠空間(最長雙倍)。
掌握字符編碼本質,才能從容應對中文處理的各種坑。
- 上一篇文章: C/C++ void 指針深度解析:泛型編程的基石
- 下一篇文章: C語言動態內存分配:malloc 完全指南與避坑指南
Copyright ©
程式碼之家 All Rights Reserved