Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix setlocale bug on unicode.md #61

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Xushi8
Copy link

@Xushi8 Xushi8 commented Oct 29, 2024

setlocale.utf-8 参数是 Windows 10 version 1803 (10.0.17134.0) 新加入的,不支持其他系统。这里提供一个godbolt 链接展示此问题。
对于 Unix-like 系统,由于其默认使用 UTF-8 编码,因此提供一个空字符串接受本地 locale 即可达到本地化的效果。

Windows .utf-8 参考链接

@Xushi8
Copy link
Author

Xushi8 commented Oct 29, 2024

人生的第一个 PR

@archibate
Copy link
Contributor

archibate commented Oct 30, 2024 via email

@Xushi8
Copy link
Author

Xushi8 commented Oct 30, 2024

但是这样确实做到了本地化,虽然对于非 UTF-8 的用户会出现问题,但是数量估计跟大熊猫有的一拼,并且这些人遇到的字符编码问题估计不止一次。
而且 Unix-like 系统貌似也无法像 Windows 夹带的私货那样直接设置成系统环境变量语言的 UTF-8 版本,因为需要首先 locale-gen 启用该语言的 UTF-8 版本。
.utf-8 参数确实在 Unix-like 系统上没有任何效果,相当于啥也没做,没有本地化的效果,跟注释不符。作为“权威指南”,应该做到正确性。

@archibate
Copy link
Contributor

setlocale(“”)是不行的,因为很多linux发行版默认的LC_ALL=C,而setlocale(“C”)会让编码格式为ASCII,使得iswspace无法判断全角空格,wcout无法输出unicode字符等。依然需要setlocale(“C.utf-8”)才能让全局函数支持unicode字符。
而且我没记错的话,setlocale(“.X”)相当于把语言保持和环境变量中的一致,但是把编码改成X。例如系统环境为zh_CN.UTF-8,setlocale(“.GBK”)会得到zh_CN.GBK。
不过这确实需要用户系统环境中有localegen过当前语言的utf8版locale,但是如果用户连utf8版locale都不生成,那大概率也是默认的“C”的locale,会使需要unicode的程序没法正常工作。
不信你可以export LC_ALL=“C”后运行setlocale(“”)试试看,看看w家族函数还能不能正常工作了。

@archibate
Copy link
Contributor

对于 Unix-like 系统,由于其默认使用 UTF-8 编码

并不是,默认都是 ASCII 编码,只不过因为大多数图形安装的发行版在选择语言的一步中就会替你设置LANG和LC_ALL,看起来好像“所有的发行版都是UTF-8”一样。我安装Arch Linux后没有经过手动配置前,就是LC_ALL=C的。

我知道.utf-8是win10某个版本引入的,确实需要提一嘴这个在之前没有支持,我的问题,但是我不认为“”是更好的选择,使用“”意味着代码里所有的字符串常量都需要为L开头的宽字符串,统一使用wcout系列接口和系统打交道,我不认为有开发者做得到,也不认为第三方库做得到。

@Xushi8
Copy link
Author

Xushi8 commented Oct 31, 2024

程序会在启动的时候执行一次 setlocale(LC_ALL, "C"),因此如果用户没有修改过系统语言的话,setlocale(LC_ALL, "") 也相当于什么都没做,只不过它会返回 "C" 而不是空指针。
由于多数人对于字符串的处理也就是普通的字符串把它当成 UTF-8 来用,需要对字符串进行进一步处理的用户肯定早就换上了宽字符串或者直接换一种语言(C/C++ 的字符串处理属实是灾难)。因此是否考虑修改通用模板,接收 setlocale(LC_ALL, "") 的返回值,判断是否是 UTF-8,如果不是就强制切换成 C.UTF-8,只不过由于返回值有好几种后缀,模板会略显复杂。Windows照旧。

@Xushi8
Copy link
Author

Xushi8 commented Oct 31, 2024

如果不是就强制切换成 C.UTF-8

修正一下,C.UTF-8 是 Linux 的扩展,Mac 不支持。对于 Mac,需要使用 UTF-8 达到相同的效果。
https://stackoverflow.com/questions/78578705/unable-to-export-lc-all-c-utf-8-on-macos

@archibate
Copy link
Contributor

archibate commented Oct 31, 2024 via email

@Xushi8
Copy link
Author

Xushi8 commented Oct 31, 2024

但是 .utf-8 真的只是 Windows 才支持啊。我刚刚测试过了,debian 12 和 ubuntu 24.04 都不支持这个,这两个应该绝对是主流吧。.utf8 无法在这两个最大的发行版本上使用,setlocale 调用失败语言用的还是默认的 C
如果仅仅只想设置 UTF-8,三大主流系统都不一样。Windows 是 .utf-8,Linux 是 C.UTF-8,Mac 是 UTF-8。这三个参数只能在对应的系统使用。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants