_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. mapreduce实现学生平均成绩

    思路: 首先从文本读入一行数据,按空格对字符串进行切割,切割后包含学生姓名和某一科的成绩,map输出key->学生姓名    value->某一个成绩 然后在reduce里面对成绩进行遍历 ...

  2. [转]Android:改变Activity切换方式

    overridePendingTransition(enterAnim, exitAnim); Intent intent =new Intent(this,item2.class); startAc ...

  3. PAT1058. A+B in Hogwarts (20)

    #include <iostream> using namespace std; int ag,as,ak; int bg,bs,bk; int cg,cs,ck; int main(){ ...

  4. vue组件 Prop传递数据

    组件实例的作用域是孤立的.这意味着不能(也不应该)在子组件的模板内直接引用父组件的数据.要让子组件使用父组件的数据,我们需要通过子组件的props选项. prop 是单向绑定的:当父组件的属性变化时, ...

  5. numpy array转置与两个array合并

    我们知道,用 .T 或者 .transpose() 都可以将一个矩阵进行转置. 但是一维数组转置的时候有个坑,光transpose没有用,需要指定shape参数, 在array中,当维数>=2, ...

  6. CEF3.2623使用记录:windows编译

    CEF3.2623使用记录:windows编译 1:cef3.2623下载地址 2623是cef3最后一个支持xp系统的版本,且可以支持html的audio标签,可以用作对html音频的处理下载地址为 ...

  7. xenapi-add-support-for-vgpu

    Model types 为了在vm中支持vgpu,问题在于vgpu是否应该被当作一个PCI设备, 虽然物理GPU不是一个SR-IOV设备,但vgpu却是以一个类似SR-IOV device上的VF赋给 ...

  8. review12

    使用StringTokenizer对象分解字符串,和split()不同的是,StringTokenizer对象不使用正则表达式作为分隔标记. 当Fenix一个字符串并将字符串分解成可被独立使用的单词时 ...

  9. spring学习-2

    Spring_属性配置细节 1.若字面值包含特殊字符,可以使用<[CDATA[]]>把字面值包裹起来 例:<value><![CDATA[<3333>^]]& ...

  10. Unity3D教程:制作与载入AssetBundle

    通常我们在游戏程式执行过程,并不希望一次将全部的资源都载入,而比较希望实际上有使用到的才载入,以免占用多余的记忆体,所以我们可能会尽量规划好不同功能的场景,在需要时才载入场景并释放掉前个场景中不需要的 ...