彻底搞懂字符编码ASCII,GB2312,UNICODE,UTF-8

2023-11-03


阅读了一篇关于编码的博客( 点击打开链接)后,自己做了下总结,解释一下基础知识

基础

能看到这篇文章, 我就假设你知道二进制,字节(byte),比特位(bit)这些概念了,如果不知道就先去了解下吧。

什么是字符编码?

我们都知道,计算机只能识别二进制,任何数据都是以二进制形式存储在计算机上的,拿现实生活中的数字为例,现实中的数字是十进制的,例如

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

在计算机上要保存为二进制形式,我们假设计算机用一个字节(也就是8个bit(一个bit表示一个二进制位))表示十进制数字,那么对应保存在计算机中的二进制就是(实际不是这么保存的,这里忽略了补码,反码,负数这些概念,因为这不是我们要讨论的重点):

0–>00000000

1–>00000001

2–>00000010

3–>00000011

4–>00000100

5–>00000101

6–>00000110

7–>00000111

8–>00001000

9–>00001001

10–>00001010

可以想到,我们用一个字节表示数字的话,一个字节共有2的8次方==256个状态,只表示正整数的话,我们可以用一个字节表示 0-255这256个正整数,这些字节是顺序存储在计算机内存中的,例如计算机保存了这么一段数据:

000010000000010100000111

计算机在识别的时候,会依次读取一个字节,例如第一个字节是00001000,表示8,同理再读取下一个字节,那么上面这段数据就认为这是857。好了,我们好像大概理解了数字是如何保存在计算机中并被计算机识别的了。

现实中除了123456这些数字,还有abcdef这些字符(以及中文字符,其他各国字符)需要计算机识别和表示,原理其实是差不多的。(字符的概念:简单通俗理解,字符为各国语言的最小单位,英语里的“a”是一个字符,中文里的"你"也是一个字符)

下面来理解一下字符编码,就是字符如何保存在计算计中并被计算机识别,和数字类似,假设我们用一个字节表示字符,例如,

我们用00000000表示a,用00000001表示b等等,计算机会一个字节一个字节的读取,读到00000000就知道这是a了,同理,一个字节有256种状态,那么一个字节就可以表示256个字符,这种把字符和相应的二进制一一对应起来,从而让计算机可以识别字符的过程,就是字符编码(实际计算机中肯定不会00000000对应a,00000001对应b这么简单的,这也是我们接下来要讨论的),可以想到,一个字节这肯定是不够的,我们有多少中文啊,其他国家还有多少字符呢。

正文

ASCII

就像基础中介绍的,ASCII是用7位bit表示字符的,所以只可以表示128个字符,一开始美国人觉得128个字符够用了。

ASCII扩展码

后来美国人发现128个字符不够用,就用8个bit(也就是一个字节)表示一个字符,那么可以表示256个字符了。

其中前128个和ASCII一模一样,后面增加128个新的字符而已,所以才叫ASCII扩展码,主要表示英文字符和一些打印字符,非打印字符等。

中国人说话了,一个字节最多256种状态,汉字远远不够表示啊。

GB2312

是对 ASCII 的中文扩展(注意是在ASCII码的基础上进行中文扩展,而不是在ASCII扩展码基础上)。也是直接存储方式。

规定把那些127号之后的奇异符号们直接取消掉(也就是取消扩展的ASCII码), 规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。 中国人民看到这样很不错,于是就把这种汉字方案叫做 “GB2312“。

GBK

把 GB2312 没有用到的码位找出来老实不客气地用上。 后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准。

DBCS

中国的程序员们看到这一系列汉字编码的标准是好的,于是通称他们叫做 “DBCS“(Double Byte Charecter Set 双字节字符集)。在DBCS系列标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里
举个例子解释两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里:

为了便于理解,我们用十进制解释,我们把a,b,c,d,e,f这6个英文字符,和“汉“,字”这两个字符用十进制编码,英文用一位十进制表示,中文用2位十进制表示:规定用单个的0-4表示英文a-e,大于4的数字,和下一位一起表示一个汉字,例如50表示“汉”,51表示“字”。那么1513350则表示“b字dd汉”,这就相当于把两位的汉字,和一位的英文共存于同一套编码方案。

ASCII系列编码是直接存储的,也就是说规定哪种字符对应哪种二进制,就把这种二进制原样存储在内存中。例如,假设编码规定00000000表示a,那么a保存在内存中就是00000000。后面会介绍UNICODE几种非直接存储(编码存储(UTF系列))

看到这,你也应该理解了,在ascii编码系列中程序员们常常念叨的一个英文字符是一个字节,一个中文字符是两个字节的含义了。

ascii编码系列最多用两个字节,最多也就表示2的16次方==65535个字符,加上其他国家的字符,还不够,怎么办?

UNICODE

Unicode也是一种字符编码方法, 不过它是由国际组织设计, 可以容纳全世界所有语言文字的编码方案。相当于为世界上每种字符都定义了一个数字来表示。
但是UNICODE虽然给每个字符都定义了一个数字表示,但是直接存储的话可能需要大于1个字节(例如假设字符a用256来表示,则存储在内存中为11111111,它是8位bit,占用了一个字节;假设字符b用257表示,则只能用两个字节表示000000100000000,同理,假如字符x用389表示呢,所以直接存储其二进制可能会造成长短不一),要将它按照字节存储,就有两个问题:

  1. 如何区分单独1个字节表示一个字符还是2个字节表示一个字符还是3个字节(注:ascii系列编码中是通过第一个字节是不是大于127来区分的)

  2. 那么为了方便区分, 如果unicode统一规定, 每个符号用三个或四个字节表示, 那么每个英文字母前都必然有二到三个字节是0, 这对于存储来说是极大的浪费,因为英文字母只用一个字节表示就够了(例如统一规定所有的字符都用三个字节表示那么字符a可能表示为000000000000000000000001,显然相比ansii编码多出了前两个字节的0很浪费),文本文件的大小会因此大出二三倍, 这是无法接受的

为了解决这两个问题,出现了UNICODE的不同编码方式,这些编码方式相当于规定了UNICODE码的存储规则,来解决上面两个问题,也就是说想办法既能很好的区分出不同的二进制表示的含义,又不那么浪费存储空间,所以需要存储UNICODE前,经过一些转换再存储,这就是UTF(Unicode Transformation Format:unicode转换格式)系列编码。

UTF-8

通过前导字节的方式(给每个字节加10标志位)来存储,既能很好的区分出不同的二进制表示的含义,又节省存储空间。是一种针对Unicode的可变长度字符编码,UTF-8用1到6个字节编码Unicode字符(所以对于UTF-8,一个字符是几个字节就不确定了,有可能是1个,2个或者3个甚至是6个)

注:关于utf-8的具体如何编码的,可以自行查看相关文档。

UTF-16(USC-2)

定死两个字节表示一个字符(显然对于英文字符会有一个字节的浪费),通常说的UNICODE就是指的UTF-16,以小端方式存储。(对于UTF-16,无论是中文还是英文,一个字符都是两个字节)

UTF-32(USC-4)

定死四个字节表示一个字符,相比UTF-16是范围更广了,表示的字符更多了,同时空间浪费也更加严重

编程语言对字符编码的支持

总结一下上面的字符编码:

  • ASCII编码的字符只需要一个字节就能存储

  • GB2312,GBK等DBCS系列需要一个或两个字节存储

  • UTF-8需要1-6个字节存储

  • UTF-16需要2个字节存储,windows中的UNICODE编码就是用UTF-16存储的,所以在VC编程中,一说UNICODE就是指UTF-16

这些需要不同存储空间的字符编码,该如何保存在程序中呢,毕竟c语言一开始只有char类型(一个字节)来表示字符,聪明的人类总是有办法,把字符编码分类:

  • ASCII,DBCS系列,utf-8等需要一个或多个存储空间的编码表示的字符串叫多字节编码字符串,用char数组保存。

  • UTF-16,也就是UNICODE,需要固定2个字节空间的编码表示的字符串叫宽字节编码字符串,用w_char数组保存,一个w_char两个字节(平台相关,在win32下w_char两个字节,在linux下wi_char是四个字节)。

有了多字节和宽字节的分类后,所有的字符串相关的操作,都有两套API分别针对多字节和宽字节,例如计算字符串长度的函数,对于多字节字符串用strlen计算,对于宽字节字符串用wcslen计算。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

彻底搞懂字符编码ASCII,GB2312,UNICODE,UTF-8 的相关文章

  • 使用 gcc 在 Linux 上运行线程构建块 (Intel TBB)

    我正在尝试为线程构建块构建一些测试 不幸的是 我无法配置 tbb 库 链接器找不到库 tbb 我尝试在 bin 目录中运行脚本 但这没有帮助 我什至尝试将库文件移动到 usr local lib 但这又失败了 任何的意见都将会有帮助 确定您
  • WPF DataGrid 多选

    我读过几篇关于这个主题的文章 但很多都是来自 VS 或框架的早期版本 我想做的是从 dataGrid 中选择多行并将这些行返回到绑定的可观察集合中 我尝试创建一个属性 类型 并将其添加到可观察集合中 它适用于单个记录 但代码永远不会触发多个
  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • 调用 McAfee 病毒扫描引擎

    我收到客户的请求 要求使用他们服务器上的 McAfee 病毒扫描将病毒扫描集成到应用程序中 我做了一些调查 发现 McScan32 dll 是主要的扫描引擎 它导出各种看起来有用的函数 我还发现提到了 McAfee Scan Engine
  • 根据属性的类型使用文本框或复选框

    如果我有这样的结构 public class Parent public string Name get set public List
  • 类型中的属性名称必须是唯一的

    我正在使用 Entity Framework 5 并且有以下实体 public class User public Int32 Id get set public String Username get set public virtual
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • 实例化类时重写虚拟方法

    我有一个带有一些虚函数的类 让我们假设这是其中之一 public class AClassWhatever protected virtual string DoAThingToAString string inputString retu
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • 在 WPF 中使用 ReactiveUI 提供长时间运行命令反馈的正确方法

    我有一个 C WPF NET 4 5 应用程序 用户将用它来打开某些文件 然后 应用程序将经历很多动作 读取文件 通过许多插件和解析器传递它 这些文件可能相当大 gt 100MB 因此这可能需要一段时间 我想让用户了解 UI 中发生的情况
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲

随机推荐

  • docker安装mongodb(单点)图文详解

    零 说明 此文档目的在于方便大家快速搭建mongodb环境 不影响使用mongodb开发或者学习 不可用于生产 一 docker安装mongodb 1 创建挂载目录 docker volume create mongo data db do
  • 电感选型的关键参数

    电感是一种储能元件 用在LC振荡电路 中低频的滤波电路 DC DC能量转换等等 其应用频率范围很少超过50MHz 从阻抗频率曲线图可知 工作频率低于谐振频率时 电感器件表现出电感性 阻抗随着频率的升高而增大 当工作频率高于谐振频率时 电感器
  • Docker部署RabbitMQ踩坑

    照网上正常部署以后 能够正常登陆 但是页面显示不全 非常痛苦 没有正常显示折线图之类的 显示不全 1 Stats in management UI are disabled on this node 解决方法 进入rabbitmq容器 do
  • 多光谱遥感分类

    多光谱遥感分类 数据集制作 SAE调参 预测 数据集制作 本次实验是多分类 9分类 训练 验证 测试数据来自人工标记的区域 用ArcGIS生成每个点的X Y地理坐标后算出像素的相对位置 data x round data X 331718
  • Umi4 从零开始实现动态路由、动态菜单

    Umi4 从零开始实现动态路由 动态菜单 前言 前期准备 数据表 Mock数据 定义类型 开始 获取路由信息 patchRoutes routes routeComponents 生成动态路由所需的数据 formattedRoutePath
  • Unity(使用GUI制作第一人称鼠标准星)

    属性 简介 方法 注意 准星一般都放在屏幕正中央 所以屏幕的 宽高 2 可得中心点 屏幕宽度 Screen Width 屏幕高度 Screen Height 矩形宽度 自己声明的变量这里使用W代替 矩形高度 自己声明的变量这里使用H代替 准
  • 全国大学生物联网设计竞赛作品

    本文分享自中移OneOS微信公众号 全国大学生物联网设计竞赛优秀作品巡展 陪你长大 智慧养鸡小助手 近几年 鸡福利养殖越来越受关注 表现动物的天性是动物福利定义之一 保证家鸡有合适的活动空间和足够的有氧运动 才能保证拥有动物的天性 对家鸡的
  • 前端项目上线优化

    1 格式化代码 使用eslint 代码检查代码的格式 vs code 想要格式化 vue 文件 需要安装 vetur插件 可以格式化代码并且变成彩色 atl shif f快捷键 vetur格式化格式化代码 还是不符合 eslint 规范 字
  • Docker容器应用日志查看

    docker attach命令 docker attach options 容器会连接到正在运行的容器 然后将容器的标准输入 输出和错误流信息附在本地打印出来 命令中options的取值有三种 detach keys no stdin si
  • 墨盒和墨仓打印机区别?

    打印机有激光打印机 喷墨打印机 针式打印机等多个种类 其中日常文件打印最长使用到的就是激光打印机和喷墨打印机 喷墨打印机分两种类 1 墨仓式喷墨打印机 2 墨盒式喷墨打印机 1 供墨方式不一样 墨盒式喷墨打印机 使用的是独立的墨盒装入打印机
  • 正大新闻:炒期货巨亏7000万引股价大跌豪悦护理回购+增持

    昨日晚间 上市公司豪悦护理发布公告称 拟以1 4亿元 2亿元回购股份 回购价格不超过75元 股 另外 其控股股东 实际控制人李志彪拟3个月内增持2000万元 5000万元 值得注意的是 通过近几日的公告可以发现 此次回购或为豪悦护理对近日因
  • 想要设计自己的微服务?看这篇文章就对了

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 本文由我就静静地看 发表于云 社区专栏 本文通过使用Spring Boot Spring Cloud和Docker构建的概念验证应用程序的示例 为了解常见的微服务架构模式提供了一个起
  • 前端练手项目合集40.0个,附源码,2022年最新

    今天分享40个博主平时收集整理的前端练手项目 都是一些适合前端新手的小项目合集 1 网易云音乐首页制作 2 实战项目之今日头条 3 实战项目之拉勾网 4 ReactNative项目之美食APP 5 uni APP项目实战教程 6 React
  • 测试人员掌握基本Linux命令——查看日志(实时日志)

    很多初级测试人员 在进行执行测试用例这个步骤时 发现bug 不能更加的准确去定位bug 在这样的情况下就可以打开Linux服务器 敲命令查看操作进行中的实时日志 当系统报错时 可以截图日志在缺陷管理系统中 开发人员就知道什么地方错了 操作步
  • rocksdb原理_ceph性能调优历程-rocksdb篇(1)

    最近调优及其他工作实在太忙 没有太多时间写心得 今天抽空来总结一下阶段性成果吧 从一开始的ceph调研 系统调优开始 ceph集群存储大规模数据之后 集群文件数超过2亿 rgw并发写性能下降的问题一直困扰我们 终于在最近找到了原因及相关解决
  • C++primer Plus 第七章复习题

    1 使用函数的3个步骤是什么 定义函数 提供原型 调用函数 2 请创建与下面的描述匹配的函数原型 igor 没有参数 且没有返回值 void igor tofu 接受一个int参数 并返回一个float float tofu int mpg
  • 去除discuz手机版链接&mobile=2后缀

    discuz手机版链接自动添加 mobile 2 导致百度收录的手机版链接无法打开 解决思路 1 打开 source class helper helper mobile php文件搜索下面代码 约在22行 content preg rep
  • malloc的底层实现(ptmalloc)

    前言 本文主要介绍了ptmalloc对于内存分配的管理 结合网上的一些文章和个人的理解 对ptmalloc的实现原理做一些总结 内存布局 介绍ptmalloc之前 我们先了解一下内存布局 以x86的32位系统为例 从上图可以看到 栈至顶向下
  • 【深度学习】_amax() got an unexpected keyword argument ‘dim‘ 解决方案

    在定义一个点云数据pc后 想使用pc max dim 0 然后出现了 amax got an unexpected keyword argument dim 这个是因为对于tensor类型的数据和ndarray类型的数据都有一个max mi
  • 彻底搞懂字符编码ASCII,GB2312,UNICODE,UTF-8

    文章目录 基础 什么是字符编码 正文 ASCII ASCII扩展码 GB2312 GBK DBCS UNICODE UTF 8 UTF 16 USC 2 UTF 32 USC 4 编程语言对字符编码的支持 阅读了一篇关于编码的博客 点击打开