宽字符wchar_t 与 窄字符char

先说下窄字符char,这个大部分读者应该很清楚,char类型的变量占一个字节(byte)(也就是8个bit(比特)),能表示256个字符,那char的范围有两种

第一种(signed char):-128~127

第二种(unsigned char):0~255

(对char的范围感兴趣的读者可以看一下这篇文章:浅谈char类型范围

但C标准并没有规定char 应该是unsigned还是signed,C标准定义了三种类型:char、signed char、unsigned char在不同的编译器下char可能是有符号数,也有可能是无符号数(意思是取决于编译器

那么怎样确定char是有符号数还是无符号数呢,有两种方法

方法一:使用CHAR_MIN(注意:CHAR_MIN这个宏是在stdlib.h这个头文件中定义的)

运行结果:

方法二:给char类型的变量赋值负数(如果char在编译器上是有符号数,那么赋值只要是大于等于-128的数都可以正常打印)

运行结果:

上述两种方法都可以用来确定char是无符号数还是有符号数(感兴趣的读者可以自行测试一下char的边界,如果char是有符号数,可以给char赋值127或128来看一下会出现什么结果)

现在来说下宽字符wchar_t,先来看下char和wchar_t在存储空间上的差别

运行结果:

从上面可以看出char占一个字节,wchar_t占两个字节

下面来确定wchar_t是有符号数还是无符号数

运行结果:

从上面的结果可以看出wchar_t为无符号数,因为wchar_t占两个字节,也就是16个比特(bit),最大值就是216-1=65535,到这里读者可以看出宽字符和窄字符最大的区别就是占字节大小的不同

宽字符 和 窄字符的赋值

关于窄字符char,大部分读者都知道赋值的方法或者

而宽字符的赋值就不太一样与窄字符相比,前面多了一个大写的L,这个L的作用就是告诉编译器,这个字符串按照宽字符来存储(一个字符占两个字节)

按照之前的说法宽字符中一个字符占2个字节,那么mm[20]应该占40个字节,长度应该为11,下面来验证一下

运行结果:

上面的代码中用到了一个函数wcslen(),这个函数和strlen()其实是一个作用,只不过strlen适用于窄字符,wcslen适用于宽字符(读者可以理解为wcslen是strlen对应的一个宽字符版本函数)

在C语言中的每个字符串处理函数都有对应的宽字符处理版本,下面列举一些常见的宽字符处理函数

(图片出处:https://www.cnblogs.com/mr-wid/archive/2012/10/07/2714392.html)

还有一点需要读者注意的是,宽字符不等于Unicode,Unicode 是宽字符编码的一种,只不过最常见的宽字符编码方式就是Unicode了,UTF-16和UTF-32都是Unicode编码。wchar_t也主要以这两种方式实现

( c/c++标准只是声明wchar_t是一个足够宽的变量类型,可以表示字符集中的任意一个字符)

Unicode 是一套字符集,而不是一套字符编码,严格来说,字符集和字符编码不是一个概念:

字符集定义了字符和二进制的对应关系,为每个字符分配了唯一的编号。可以将字符集理解成一个很大的表格,它列出了所有字符和二进制的对应关系,

计算机显示文字或者存储文字,就是一个查表的过程。

而字符编码规定了如何将字符的编号存储到计算机中。如果使用了类似 GB2312 和 GBK 的变长存储方案(不同的字符占用的字节数不一样),那么为了区分一个字符

到底使用了几个字节,就不能将字符的编号直接存储到计算机中,字符编号在存储之前必须要经过转换,在读取时还要再逆向转换一次,这套转换方案就叫做字符编码

Unicode最长是32位,也就是4个字节,因为UTF-8是1~6个字节来存储,当使用5或6字节存储时,就不属于Unicode编码了

(感兴趣的读者可以看一下:刨根问底:C++中宽字符类型(wchar_t)的编码一定是Unicode?长度一定是16位?

宽字符输出函数

wprintf

wprintf无非就是printf的一个变种,和fprintf差不多只是格式上稍有区别

运行结果:

上面的代码中,wprintf使用的格式控制符是%ls,%ls意味着将对应的参数会被当作基于宽字符的字符串(wide chraracter string )看待,而%s则意味着对应的参数会被当作普通字符串(multi-byte string)看待,

不要因为上面一句话而错误的认为%s只用于printf,而%ls只用于wprintf,其实在windows下使用都是可以正常输出宽字符串的(其他操作系统下就不一定了)

%s
当使用 printf() 时,按照单字符格式输出字符串
当使用 wprintf() 时,按照宽字符(两字节)格式输出字符串

%S
当使用 printf() 时,按照宽字符格式输出字符串
当使用 wprintf() 时,按照单字符格式输出字符串

注意这个H是宽字符串mm中的H,而不是ss中的H,ss中的字符串中的每个字符占一个字节,printf如果按照宽字符的标准来输出就无法正常输出了,而wprintf为什么只输出了H呢,不是输出字符串吗,

下面我们用VS来看宽字符在内存中的存储

从上图就可以很清楚的看出“Hello World”这个宽字符串在内存中的存储情况了,因为是宽字符所以大写字母H用两个字节表示(48 00),48是16进制转成10进制就是72,刚好就是'H'的ASCII码值的大小,如果按照单字符格式输出(也就是一个字节一个字节的输出)就输出H,继续往后,编译器看到第二个字节00,就以为字符串已经到结束了,最后我们看到的结果就是只输出了大写字符H

 (本来对%S没有什么疑问,就当成一个格式控制符记住就是,后来在微软的官方文档里找到了%S这个参数的解释,如下图)

上面这段话的意思大概是,%S这个格式说明符,表示使用与函数支持的默认宽度“相反”的字符宽度,有了这一段话,上面的就很好解释了,printf因为默认支持的宽度是单字符,而%S偏要使用相反的,那么就

使用宽字符格式输出,而wprintf默认支持的宽度是宽字节,%S偏要使用相反的,意思就是使用单字符格式输出,这样记起来就容易多了

如果想要输出宽字符的单个字符,需要使用格式控制符%lc

(要清楚%ls和%s的意义在于指明的参数是何种字符串,而printf和wprintf的区别在于所使用的是不同类型的stream,不要混用 char 和 wchar_t 版本的流操作函数,否则会导致这些函数运行异常)

putwchar

putwchar函数专门用来输出一个宽字符,它和 putchar 的用法类似

wchar_t ch = L'Z';
putwchar(ch);

运行结果:

宽字符wchar_t和窄字符char——putwchar、wprintf的更多相关文章

  1. C++ 宽字符(wchar_t)与窄字符(char)的转换

    了解 长度 宽字符wchar_t的长度16位,可以用来显示中文等除英文外的其他文字, 窄字符    char   的长度  8 位,只能处理英文. 哪里可以见到 在VS2010, 2012, 2013 ...

  2. 宽字符wchar_t和窄字符char区别和相互转换

    转自:http://blog.csdn.net/nodeathphoenix/article/details/7416725 1.    首先,说下窄字符char了,大家都很清楚,就是8bit表示的b ...

  3. GBK转utf-8,宽字符转窄字符

    //GBK转UTF8 string CAppString::GBKToUTF8(const string & strGBK) { string strOutUTF8 = "" ...

  4. C语言小程序——推箱子(窄字符和宽字符)

    C语言小程序——推箱子(窄字符Version) 推箱子.c #include <stdio.h> #include <conio.h> #include <stdlib. ...

  5. volatile,可变参数,memset,内联函数,宽字符窄字符,国际化,条件编译,预处理命令,define中##和#的区别,文件缓冲,位域

    1.volatile: 要求参数修改每次都从内存中的读取.这种情况要比普通运行的变量需要的时间长. 当设置了成按照C99标准运行之后,使用volatile变量之后的程序运行的时间将比register的 ...

  6. 使用Unicode(宽字节字符集);多字节字符集中定义宽字节变量

    2012-03-25 14:54 (分类:计算机程序) 2.2 宽字符和C 宽字符不一定是Unicode.Unicode是宽字符集的一种.然而,因为本书的焦点是Windows而不是C执行的理论,所以书 ...

  7. 计算字符串中每种字符出现的次数[Dictionary<char,int>泛型集合用法]

    有一道经典的面试题: 统计 welcome to china中每个字符出现的次数,不考虑大小写.      第一个出现在脑海里的想法是: 1. 将字字符串转换成 char数组: 2. 用 for循环遍 ...

  8. strlen 字符型数组和字符数组 sizeof和strlen的区别 cin.get(input,Arsize)

    strlenstrlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符'\0'为止,然后返回计数器值 ...

  9. 有一字符串,包含n个字符。写一函数,将此字符串中从第m个字符开始的全部字符复制成为另一个字符串。

    [提交][状态][讨论版] 题目描述 有一字符串,包含n个字符.写一函数,将此字符串中从第m个字符开始的全部字符复制成为另一个字符串. 输入 数字n 一行字符串 数字m 输出 从m开始的子串 样例输入 ...

随机推荐

  1. angular中使用ckplayer播放器

    原文地址:https://www.cnblogs.com/jying/p/9519557.html ,转载请说明出处. ckplayer官网:http://www.ckplayer.com 使用ckp ...

  2. 吴裕雄 python深度学习与实践(9)

    import numpy as np import tensorflow as tf inputX = np.random.rand(100) inputY = np.multiply(3,input ...

  3. redis make编译失败的原因

    make clean redis编译失败可能是: 1.未安装gcc,gcc-c++ yum install gcc yum install gcc-c++ 2.未安装tcl yum install t ...

  4. DOM 节点node

    DOM可以将任何HTML或XML文档描绘成一个有多层节点构成的结构,即在HTML中所有内容都是节点.文档节点是每个文档的根节点,文档节点有一个子节点,称为文档元素.每个文档只能有一个文档元素.在HTM ...

  5. mysql学习笔记--数据库设计

    一.数据库基本概念 1. 关系:两个表的公共字段 2. 行:也称记录,也称实体 3. 列:也称字段,也称属性 4. 数据冗余:相同的数据存在不同的地方. 注意:冗余只能减少,不能杜绝. 减少冗余,只能 ...

  6. 回忆Partition算法及利用Partition进行快排

    一.Partiton算法 Partiton算法的主要内容就是随机选出一个数,将这个数作为中间数,将大于它的排在它右边,小于的排在左边(无序的). int partition (int arr[],in ...

  7. Power designer 的使用

    1.Powere Designer 逆向 工程 首先 逆向工程 就是将数据库表 导入到模型, 首先新建个模型, 此处就省略 ... 工具栏,数据库(database) 下的 update model ...

  8. kalman滤波(三)---各种滤波的方法汇总+优化的方法

    大神解答 一.前提 最一般的状态估计问题,我们会根据系统是否线性,把它们分为线性/非线性系统.同时,对于噪声,根据它们是否为高斯分布,分为高斯/非高斯噪声系统.现实中最常见的,也是最困难的问题,是非线 ...

  9. node.js中使用socket.io + express进行实时消息推送

    socket.io是一个websocket库,包含客户端的js和服务端的node.js,可以在不同浏览器和移动设备上构建实时应用. 一.安装 socket.io npm install socket. ...

  10. MySQL开发——【数据库、数据表的基本操作】

    启动MySQL服务器端 CMD启动MySQL服务器端 net start(启动)|stop(停止)|restart(重启)服务名称(mysql) 连接MySQL服务器端 CMD连接MySQL服务器端 ...