首页 > 代码库 > _tprintf(), printf(),wprintf() 与控制字符 %s 和 %S(Unicoe与GB2312))
_tprintf(), printf(),wprintf() 与控制字符 %s 和 %S(Unicoe与GB2312))
_tprintf() 是 printf() 和 wprintf() 的通用类型;如果定义了 _unicode,那么 _tprintf() 就会转换为 wprintf(),否则为 printf() 。
在这 3 个函数中有两个字符串控制输出字符为 %s 和 %S 。使用它们时,有如下区别:
%s
当使用 printf() 时,按照单字符格式输出字符串。
当使用 wprintf() 时,按照宽字符(两字节)格式输出字符串。
%S
当使用 printf() 时,按照宽字符格式输出字符串。
当使用 wprintf() 时,按照单字符格式输出字符串。
这里,所谓的 “单字符” 格式,就是指按照字节的原始样式输出,而 “宽字符” 则是按照 Unicode 码双字节的样式输出。举一个例子,当按照 “单字符” 样式输出时,如果你的系统是简体中文,采用 GB2312 编码,那么如果输出的连续两个字节组合起来刚好可以形成一个合法的 GB2312 编码,那么它就显示为一个汉字。如果是按照“宽字符”样式输出,一次输出两个字节,且假设这两个字节的 Unicode 码刚好若能正常转换为相应的 GB2312 码,且在程序里使用了 setlocale() 函数将程序的 locale 设为和系统默认 locale 一致时,那么输出的 Unicode 码则可以被自动转换为 GB2312 码,这时也可以正常显示出汉字。
下面举例演示上述情况。
程序-1:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | int _tmain( int argc, _TCHAR* argv[]) { CHAR buffer[20] = {}; buffer[0] = 0xcc; buffer[1] = 0x96; /* “雌” 的 Unicode 码*/ buffer[2] = 0xb4; buffer[3] = 0xdf; /*“催” 的 GB2312 码*/ buffer[4] = ‘\0‘ ; printf ( "\n--%s" , buffer); printf ( "\n==%S" , buffer); wprintf (L "\n-=%S" , buffer); wprintf (L "\n=-%s" , buffer); return 0; |
首先,0x96CC 是 “雌” 字的 Unicode 码,该字的 GB2312 码为 0xB4C6 。0xB4DF 是 “催” 字的 GB2312 码。
运行上面程序:
D:\WindowsAPP\setfp\Debug>setfp.exe
--號催
==
-=號催
=-??
分析上面的输出结果。首先我们使用 printf() 并以 %s 的格式打印出数组 buffer[] 里的内容,上面说过 %s 是以单字符格式输出的,换句话来说,我们这里顺序输出了 0xcc, 0x96, 0xb4, 0xdf 这 4 个字节。因为 GB2312 的编码也是两个两个字节编码的,而我们的命令行里使用的编码也是 GB2312,因此前面的 0xcc 和 0x96 所组成的 0xcc96 并不在 GB2312 码表内(GB2312 码的低字节不小于 0xA0),所以它不能显示为 GB2312 里所列的常用汉字。而接下来的一组 0xb4df 就可以正常的解析为汉字 “催” 字。
那么当我们用 printf() 并以 %S 格式输出时(这里只输出了 "==" 而后面内容不可见),尽管上面的 0xCC96 符合汉字 "雌“ 编码,但 C 语言默认的 locale 并不支持汉字的显示,所以要先用 setlocale() 函数进行 locale 的设定,使程序所用 lacale 和系统默认的一致,这样 Unicode 码就能被正常解析为相应的 GB2312 码,从而正确显示出汉字来。这个情况会在程序2里做演示。
第 3 个行我们用 wsprintf() 并以 %S 的格式控制输出,上面说过,此时 wprintf() 是按照 ”单字符“ 格式输出的,因此和 "printf() + %s" 的情况一样。
第 4 行我们使用 wsprintf() 并以 %s 的格式控制输出,此时 wprintf() 是按照 ”宽字符“ 样式输出的,由于我们这里没有使用 setlocale() 的缘故,0xcc96 无法显示出汉字,而最后的组合 0xb4df 这个码(注意,此处已经被认为是 Unicode 形式) 并没有相应的汉字对应,况且也没有实现 setlocale() ,那自然是无法识别。
下面的程序对上面的 示例-1 稍作修改(示例-2),即加上 setlocale() 函数后,再运行看下输出:
D:\WindowsAPP\setfp\Debug>setfp.exe
--號催
==雌
-=號催
=-雌?
这时候,我们看到第一行的 "printf() + %s" 的输出和 示例-1 的情况一样,由此可见,setlocale() 并不会影响单字节输出时对 GB2312 码的转换,因为它本身就是要求对输出的字节按照 GB2312 码来解析的。
现在在第 2 行里,我们看到,"printf() + %S" 已经可以输出汉字 ”雌“ 了,这是因为 setlocale() 可以使 Unicode 码可以转换为 GB2312 的缘故,而后面的 0xb4df 被当做 Unicode 码看待,因而没法转换为合适的 GB2312 码,因此没法显示。
第 3 行的输出和第 示例-1 中的输出及道理一样。
第 4 行是以 "wprintf() + %s" 输出,这时 wprintf() 以 ”宽字符“ 样式输出,因此 ”雌” 字可以正常显示,同理后面的字符无法显示。