_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

[C++] 纯文本查看 复制代码
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() 以 ”宽字符“ 样式输出,因此 ”雌” 字可以正常显示,同理后面的字符无法显示。

_tprintf(), printf(),wprintf() 与控制字符 %s 和 %S(Unicoe与GB2312))的更多相关文章

  1. C++ Unicode SBCS 函数对照表

    C++ Unicode SBCS 函数对照表,以备日后查阅 Generic SBCS UNICODE TCHAR char wchar_t _TEOF EOF WEOF _TINT int wint_ ...

  2. C++ Unicode SBCS 函数对照表,以备日后查阅(很全)

    C++ Unicode SBCS 函数对照表,以备日后查阅 Generic SBCS UNICODE TCHAR char wchar_t _TEOF EOF WEOF _TINT int wint_ ...

  3. printf打印输出null问题的跟踪

    最近在工作中,遇到一处 printf输出有null的情况,在此记录一下,问题分析的过程. 测试代码很简单,本机为64位操作系统: #include <stdio.h> #include & ...

  4. ANSI 和 UNICODE 的函数对应表

    ANSI        UNICODE           通用(char.h)    (wchar.h)        (tchar.h) char         wchar_t         ...

  5. 【C++】wchar、char格式化符输出

    VC.BCB.MinGW Linux下的GCC.C99标准 printf wprintf printf wprintf s char wchar_t char S wchar_t char * hs ...

  6. VC++关于UNICODE版本的开发

    关于UNICODE版本的开发 代码转换方案 概述 在VC6.0中,相应的有一些宏来代替ANSI的函数.宏或数据类型,这些宏在ANSI编译条件中处理字符串为单字节,而在UNICODE中处理字符串为双字节 ...

  7. c++ wchar_t

    ·C语言相关 对应于char, C语言中也有宽字符内型wchar_t.wchar_t被定义为: typedef unsigned short wchar_t ;显然它是16位的.wchar_t类型的常 ...

  8. C++/VC中ANSI与UNICODE中字符定义和函数对照表

    这样查起来方便多了 ANSI UNICODE 通用 说明 数据类型 (char.h) (wchar.h) (tchar.h)   char wchar_t TCHAR   char * wchar_t ...

  9. 使你的C/C++代码支持Unicode(CRT字符串处理的所有API列表,甚至有WEOF字符存在)

    悉Microsoft支持Unicode的方式. 它的主要目的是方便你查询相关的数据类型和函数,以及修正相应的拼写错误. I18nGuy 主页 XenCraft (Unicode 咨询公司) Engli ...

随机推荐

  1. java 项目中每个jar包的作用总结

    别人的总结 1.Struts2 1)commons-fileupload :2)common-io:文件上传 3)commons-lang:它扩展了标准 java.langAPI ArrayUtils ...

  2. HDU 3966 & POJ 3237 & HYSBZ 2243 & HRBUST 2064 树链剖分

    树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...

  3. WIN7 X64 PASSUAC 源码

    // Passuac.cpp : Defines the entry point for the console application. // #include "stdafx.h&quo ...

  4. waitpid使用的一点问题

    使用waipid的时候遇到了一个奇怪的问题,将情况简化后描述一下. 有关waitpid的基本介绍参见这里一下:http://www.cnblogs.com/mickole/p/3187770.html ...

  5. linux命令:rm 命令

    昨天学习了创建文件和目录的命令mkdir ,今天学习一下linux中删除文件和目录的命令: rm命令.rm是常用的命令,该命令的功能为删除一个目录中的一个或多个文件或目录,它也可以将某个目录及其下的所 ...

  6. Codeforces Round #374 (Div. 2) D. Maxim and Array 线段树+贪心

    D. Maxim and Array time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  7. (转) 一次批量重启引发的Neutron网络故障

    现场回顾 故事发生于某个下午,采用 salt 更新某集群的 neutron.conf (log 相关配置项) 并批量重启 neutron-openvswitch-agent(以下简称 neutron- ...

  8. 【转载】JAVA中线程的两种实现方法-实现Runnable接口和继承Thread类

    转自: http://blog.csdn.net/sunguangran/article/details/6069317 非常感谢原作者,整理的这么详细. 在java中可有两种方式实现多线程,一种是继 ...

  9. js的深拷贝特别注意this的深拷贝

    原生的,jquery的extend,和angular的copy 我们深拷贝的根本原因是为了不改变原来对象的值. <script type="text/javascript"& ...

  10. 算法练习4---冒泡排序java版

    冒泡排序的基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒.即:每当两相邻的数比较后发现它们的排序与排序要求相反 ...