> 文章列表 > 使用wchar和wprintf

使用wchar和wprintf

使用wchar和wprintf

成功在Linux下和Windows下都运行起来了,给个例子:

#include <stdio.h>
#include <locale.h>
#include <wchar.h>int main (void)
{setlocale (LC_ALL, "");wprintf (L"你好世界!\\n");
}

重点主要是:

  1. 要设定区域(使用setlocale(),否则会乱码)
  2. 宽窄不能混用

细节问题很多,我这里只说结果了,原因可以看后面的参考链接。

不注意细节的话可能会:只能输出英文、什么都不输出、中文乱码/变成问号、有的输出消失。

1. wchar_t和char

首先,char是一个字节wchar_t是多个字节。
wchar_t字节数不固定,windows是2字节,gcc是4个字节),实际上gcc的wchar_t实现是int类型。

2. %ls,%s和 L""

  • 先说L""

    wchar_t wstr[] = L"你好";
    

    为什么要加这个前缀?因为"你好"表示的类型是const char*,加上L后才表示const wchar_t *

  • %s 和%ls的认知误区
    初看时很容易误解,以为%s是printf()用的,%ls是给wprintf()用的,实则不然printf()也可以用%lswprintf()也可以用%s

举个例子:

#include <stdio.h>
#include <locale.h>int main (void)
{setlocale (LC_ALL, "");// printf ("%ls", "你好"); // 错误写法printf ("%ls", L"你好");// 你好
}

先别管那个setlocale()

第一个注释的,它没有加L,但是前面又用了%ls%ls按宽字符wchar_t来解读窄字符char,自然得不到想要的结果。

第二个,后面用了L前缀,表示把一个宽字符字面量的,前面也用了%ls来正确解读它,正确。

UTF-8将英文按一个字节算,汉字按3个字节算,所以,"你好"是7个字节(还有个终止符).
L"你好",在gcc的实现中是 4 + 4 + 1 = 9个字节。

加不加L只是解读方式不同。

但是也要看清楚了,不要稀里糊涂乱加,
printf(format, ...)显然format得是const char*,不能这样:printf(L"nihao"),后面的可变参数可以是任意类型,当然可以是宽字符,只不过用宽字符的话前面就要用对应的格式符%ls
wprintf()的格式字符串就必须要L,后面要不要和printf一个道理。

3. 设置区域

实测时如果不写setlocale()是用不了宽字符的,会没有输出 / 乱码。

看其他人说是C99的标准规定。

想了想也确实合理,因为要做宽窄转换,宽窄转换函数会受setlocale()设置的区域所影响。

4. 宽窄不能混用

#include <stdio.h>
#include <locale.h>int main (void)
{setlocale (LC_ALL, "");printf ("printf\\n");wprintf (L"wprintf\\n"); 
}

运行你就会发现只输出了printf,第二个wprintf没有输出。
原因是一个流会和一个宽窄绑定,具体细节不清楚。
用的时候只能用一个宽度的流,剩下的那一个如果也想用,就用宽窄转换函数来辅助。

要获取宽度,使用fwide()

(然而实测时,Windows宽窄混用没问题,linux下混用只有一个有效,一言难尽…… )

参考链接

关于wchar_t(这篇比较有用,强推)
关于宽窄不能混用的问题
关于流的实现不能是面向字节 https://man7.org/linux/man-pages/man3/wprintf.3.html
关于setlocale()解决wprintf()不显示