在今天,大量使用java与.net的程序员已经很少去真实了解字符的底层表达,但是使用VC++编程,对字符的处理却非常慎重,刚学习vc++肯定会为其中的字符类型给晕头转向,今天本人学习第一节,从字符开始
特别说明:本文章所有开发环境选用vs2012开发
在计算机系统中所有的数据与程序指令都是二进制的形式存在的,CPU处理器给特定序列的二进制序列包含有特殊的意义,及我们常说的计算机指令,计算机指令目前流行的X86指令集,以及目前流行android平台下arm指令集,同时所有的数据也是以二进制的形式表达在计算机中,主要表达在计算机体系中的内存,寄存器,以及CPU缓存。所以计算机认识到的字符也就是一串二进制格式的数据,计算机的首要任务就是给这些二进制进行字符的映射,但是在不同的指令集与CPU下,对这些二进制进行翻译的过程中又产生了高位与低位只说,这个只是CPU级别的二进制读取顺序,如何给这些特定的二进制翻译成我们熟悉的人类语言,于是就产生了我们经常所说的字符串编码,常用的有ASCII编码,以及Unicode,
asccii编码,及单个字节编码,1个字节8个位,也就是说,在计算机内存中,8个连续的位能代码一个字符,那么如何映射成字符呢,那么就是通过我们的assicc表来实现,如下
八进制 | 十六进制 | 十进制 | 字符 | 八进制 | 十六进制 | 十进制 | 字符 |
---|---|---|---|---|---|---|---|
00 | 00 | 0 | nul | 100 | 40 | 64 | @ |
01 | 01 | 1 | soh | 101 | 41 | 65 | A |
02 | 02 | 2 | stx | 102 | 42 | 66 | B |
03 | 03 | 3 | etx | 103 | 43 | 67 | C |
04 | 04 | 4 | eot | 104 | 44 | 68 | D |
05 | 05 | 5 | enq | 105 | 45 | 69 | E |
06 | 06 | 6 | ack | 106 | 46 | 70 | F |
07 | 07 | 7 | bel | 107 | 47 | 71 | G |
10 | 08 | 8 | bs | 110 | 48 | 72 | H |
11 | 09 | 9 | ht | 111 | 49 | 73 | I |
12 | 0a | 10 | nl | 112 | 4a | 74 | J |
13 | 0b | 11 | vt | 113 | 4b | 75 | K |
14 | 0c | 12 | ff | 114 | 4c | 76 | L |
15 | 0d | 13 | cr | 115 | 4d | 77 | M |
16 | 0e | 14 | so | 116 | 4e | 78 | N |
17 | 0f | 15 | si | 117 | 4f | 79 | O |
20 | 10 | 16 | dle | 120 | 50 | 80 | P |
21 | 11 | 17 | dc1 | 121 | 51 | 81 | Q |
22 | 12 | 18 | dc2 | 122 | 52 | 82 | R |
23 | 13 | 19 | dc3 | 123 | 53 | 83 | S |
24 | 14 | 20 | dc4 | 124 | 54 | 84 | T |
25 | 15 | 21 | nak | 125 | 55 | 85 | U |
26 | 16 | 22 | syn | 126 | 56 | 86 | V |
27 | 17 | 23 | etb | 127 | 57 | 87 | W |
30 | 18 | 24 | can | 130 | 58 | 88 | X |
31 | 19 | 25 | em | 131 | 59 | 89 | Y |
32 | 1a | 26 | sub | 132 | 5a | 90 | Z |
33 | 1b | 27 | esc | 133 | 5b | 91 | [ |
34 | 1c | 28 | fs | 134 | 5c | 92 | \ |
35 | 1d | 29 | gs | 135 | 5d | 93 | ] |
36 | 1e | 30 | re | 136 | 5e | 94 | ^ |
37 | 1f | 31 | us | 137 | 5f | 95 | _ |
40 | 20 | 32 | sp | 140 | 60 | 96 | ' |
41 | 21 | 33 | ! | 141 | 61 | 97 | a |
42 | 22 | 34 | " | 142 | 62 | 98 | b |
43 | 23 | 35 | # | 143 | 63 | 99 | c |
44 | 24 | 36 | $ | 144 | 64 | 100 | d |
45 | 25 | 37 | % | 145 | 65 | 101 | e |
46 | 26 | 38 | & | 146 | 66 | 102 | f |
47 | 27 | 39 | ` | 147 | 67 | 103 | g |
50 | 28 | 40 | ( | 150 | 68 | 104 | h |
51 | 29 | 41 | ) | 151 | 69 | 105 | i |
52 | 2a | 42 | * | 152 | 6a | 106 | j |
53 | 2b | 43 | + | 153 | 6b | 107 | k |
54 | 2c | 44 | , | 154 | 6c | 108 | l |
55 | 2d | 45 | - | 155 | 6d | 109 | m |
56 | 2e | 46 | . | 156 | 6e | 110 | n |
57 | 2f | 47 | / | 157 | 6f | 111 | o |
60 | 30 | 48 | 0 | 160 | 70 | 112 | p |
61 | 31 | 49 | 1 | 161 | 71 | 113 | q |
62 | 32 | 50 | 2 | 162 | 72 | 114 | r |
63 | 33 | 51 | 3 | 163 | 73 | 115 | s |
64 | 34 | 52 | 4 | 164 | 74 | 116 | t |
65 | 35 | 53 | 5 | 165 | 75 | 117 | u |
66 | 36 | 54 | 6 | 166 | 76 | 118 | v |
67 | 37 | 55 | 7 | 167 | 77 | 119 | w |
70 | 38 | 56 | 8 | 170 | 78 | 120 | x |
71 | 39 | 57 | 9 | 171 | 79 | 121 | y |
72 | 3a | 58 | : | 172 | 7a | 122 | z |
73 | 3b | 59 | ; | 173 | 7b | 123 | { |
74 | 3c | 60 | < | 174 | 7c | 124 | | |
75 | 3d | 61 | = | 175 | 7d | 125 | } |
76 | 3e | 62 | > | 176 | 7e | 126 | ~ |
77 | 3f | 63 | ? | 177 | 7f | 127 | del |
其中,每一个二进制序列对应这一个英文与数字字符,例如常说的十进制数65的二进制表达是1000001,对应的十六进制为0x41;
我们都知道c语言中,字符是用char类型表示,同时默认的编码格式为asccii编码,也就是说当0x41这个十六进制数在转换成整形值是65,在进行asccii字符转换时,如上表所示,即我们常说的大写字母A,
下面我们做一个实验,即可证明以上观点是否正确
#include "stdafx.h" int _tmain(int argc, _TCHAR* argv[])
{
//数值数据
int i=0x41;
//内存数据按整形值翻译打印出来
printf("this is int%d\n",i);
//内存数据按照asccii翻译打印出来
printf("this is char%c\n",i);
//打印出内存数据的十六进制格式
printf("this is binary 0x%x\n",i);
return ;
}
打印结果如下
由此可见,数据的表达都是二进制,只是人为的定义了一些一些含义,你认为是字符的时候,就转换成字符,你认为是数字的时候就变成了数字,你认为是指令的时候,就编程了是指令,只是指令已经被CPU确定了含义。
那么同理得出Unicode也是类似的结构,只是有点不同
1、Unicode为双字节编码,也就是说一个字符需要两个字节的容量才能保存
所以需要特别注意的地方到了,那么以上这些函数printf能处理Unicode字符串吗?
答案显然是不能的,我们依然写一个程序去验证我们的结果
#include "stdafx.h"
#include <Windows.h> int _tmain(int argc, _TCHAR* argv[])
{
WCHAR unicodeChar='很';
printf("this is unicode Char%c\n",unicodeChar); return ;
}
打印的结论:
可以看到,最终被一个问号代替了,也就是说,printf函数并没有把他解析出来,它依然按照asccii标准去解析,所以变成了问号,那么疑问出来了
WCHAR到底是一个什么类型呢,怎么在c++标准中并不存在这样一个类型呢?
答案马上揭晓,我们找到了下面的宏定义
#ifndef _MAC //非苹果硬件平台
typedef wchar_t WCHAR; //实际值是wchar_t // wc, 16-bit UNICODE character
#else
// some Macintosh compilers don't define wchar_t in a convenient location, or define it as a char
typedef unsigned short WCHAR; //苹果硬件平台实际上是unsigned short
// wc, 16-bit UNICODE character #endif
也就是如上所述:
所以在我们常用的电脑下,都是wchar_t类型,那么这又是一个什么类型呢?