在Linux下用GCC打印Unicode字符及UTF-16文件打印的问题
问题分析与解决方案
代码存在的核心问题
-fshort-wchar与glibc标准IO不兼容:Linux系统默认wchar_t是32位,glibc的printf("%ls")等函数是针对32位wchar_t实现的。你用-fshort-wchar强制将wchar_t改为16位后,printf无法正确解析16位宽字符数据,导致后续输出无内容。- 宽字符数组初始化错误:
wchar_t sample1[] = { L"..." };的写法错误——花括号把宽字符串字面量(本质是const wchar_t*)当成单个元素存入数组,实际得到的是仅包含指针的数组,而非预期的宽字符序列,这也会导致打印异常。
修复当前打印问题的步骤
1. 移除-fshort-wchar编译选项
Linux下处理宽字符应遵循系统默认的32位wchar_t,不要强制修改宽度。如果需要兼容Windows的UTF-16数据,应在读取后做编码转换,而非修改wchar_t的宽度。
2. 修正宽字符数组初始化
去掉多余的花括号,正确声明宽字符数组:
wchar_t sample1[] = L"Sample TEXT\\自己人自己人人 AZZZZZZZA己中国中中中\n";
3. 验证修复后的代码
修改后的完整代码:
#include <stdio.h> #include <wchar.h> #include <locale.h> int main(void) { setlocale(LC_ALL, "en_US.UTF-8"); wchar_t sample1[] = L"Sample TEXT\\自己人自己人人 AZZZZZZZA己中国中中中\n"; printf("AAAA\n"); printf("%ls", L"ABCD"); printf("%ls", sample1); return 0; }
编译命令:
gcc test.c -o test
运行后就能正常输出所有宽字符内容。
处理Windows UTF-16文件的读取与打印
Windows下的UTF-16文件通常带BOM(字节顺序标记),读取时需先处理字节序,再将UTF-16转换为Linux终端支持的UTF-8输出,这种方式比依赖宽字符函数更可靠:
示例代码(读取UTF-16文件并打印)
#include <stdio.h> #include <stdlib.h> #include <iconv.h> #include <string.h> #define BUFFER_SIZE 1024 int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <utf16-file>\n", argv[0]); return 1; } FILE *fp = fopen(argv[1], "rb"); if (!fp) { perror("fopen failed"); return 1; } // 跳过UTF-16 BOM(如果存在) unsigned char bom[2]; if (fread(bom, 1, 2, fp) == 2) { if (!(bom[0] == 0xFF && bom[1] == 0xFE) && !(bom[0] == 0xFE && bom[1] == 0xFF)) { // 无BOM或BOM无效,重置文件指针 fseek(fp, 0, SEEK_SET); } } // 初始化iconv,将UTF-16LE(Windows常用)转换为UTF-8 iconv_t cd = iconv_open("UTF-8", "UTF-16LE"); if (cd == (iconv_t)-1) { perror("iconv_open failed"); fclose(fp); return 1; } char in_buf[BUFFER_SIZE], out_buf[BUFFER_SIZE * 2]; size_t in_left, out_left; char *in_ptr, *out_ptr; while ((in_left = fread(in_buf, 1, BUFFER_SIZE, fp)) > 0) { in_ptr = in_buf; out_ptr = out_buf; out_left = sizeof(out_buf); if (iconv(cd, &in_ptr, &in_left, &out_ptr, &out_left) == (size_t)-1) { perror("iconv failed"); break; } // 输出转换后的UTF-8内容 fwrite(out_buf, 1, sizeof(out_buf) - out_left, stdout); } iconv_close(cd); fclose(fp); return 0; }
编译命令:
gcc utf16_to_utf8.c -o utf16_to_utf8 -liconv
运行方式:
./utf16_to_utf8 your_windows_utf16_file.txt
说明
- 使用
iconv库进行编码转换,这是Linux系统处理不同编码的标准工具。 - 处理UTF-16字节序:Windows默认是UTF-16LE,代码中优先按此转换;如果文件是UTF-16BE,只需将
iconv_open的第二个参数改为"UTF-16BE"。 - 转换为UTF-8后直接用
fwrite输出,无需依赖宽字符函数,适配性更强。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

