随着技术的发展,越来越多开发者转向使用 Windows Subsystem for Linux(WSL)在 Windows 10 上进行开发,也就是说不用虚拟机,不用准备多一台电脑,只需要在Windows 10/11 里安装 WSL 就能体验 Linux 系统。因此我在 Win10 系统里安装了Ubuntu 20 系统学习 Linux 基础,可以用来编译 C / C++ 代码,体验同一个代码编译运行与 Windows 环境下的差别。
之前就听说 WSL 有一些潜在的限制,无论性能还是功能都不能100%取代裸机 Linux 系统。今天就被我逮到 WSL 下的 Ubuntu 的一个缺点:输出宽字符串(wide string)时失败。
比如下面一段把普通字符串转换成宽字符串的 C 代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>
int main() {
// Windows环境下要设为 setlocale(LC_ALL, "en-US.UTF-8");
// Linux环境下设为 setlocale(LC_ALL, "");
// 设置不当的话,转换后的宽字符串长度不正确
setlocale(LC_ALL, "");
char* str = "22年2月22日";
int len = strlen(str);
printf("narrow string: %s\n", str);
printf("narrow string length: %d\n", len);
wchar_t* wstr = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
size_t wlen = mbstowcs(wstr, str, len+1);
wprintf(L"wide string: %ls\n", wstr);
printf("wide string length: %zu\n", wlen);
for(size_t i=0; i<wlen; i++)
wprintf(L"%lc\t%d\n", wstr[i], (int)wstr[i]);
free(wstr);
return 0;
}
这段代码将普通字符串“22年2月22日”转换成宽字符串格式,得出正常的长度为8,然后输出各个字符值。在 Windows 环境下,必须在主程序里设置setlocale(LC_ALL, "en-US.UTF-8");
或者setlocale(LC_ALL, "zh-CN.UTF-8");
,使用 clang 编译运行的结果才能正常:
到了 WSL 的 Ubuntu 环境,由于Ubuntu终端的字符编码默认是UTF-8,因此主程序中要把 LC_ALL
后面的字符串置空:setlocale(LC_ALL, "");
,然后编译运行:
转换后的宽字符串长度是8,这是正确的,但是无法输出转换后的字符串以及每个字符对应的值。我尝试了各种办法修改 wprintf 和 printf 语句,但输出结果无济于事,令人百思不得其解。
直到后来我在安卓手机上安装了Termux
(一款运行于安卓系统的 Linux 模拟器),然后在手机上运行 clang 编译再运行 ~~ 结果一切正常了。
换了环境,豁然开朗!
由此可见 Windows 10 的 WSL(Ubuntu) 在处理特定操作时确实有其局限性。