字符
定义
字符数据类型是编程语言中表示单个字符的基本类型,其取值是某个字符集中的一个编码点,而不是字形或字体的描述。Java 的 char 用 16 位存放一个 UTF-16 代码单元,取值范围为 \u0000 到 \uffff[2]。Visual Basic 的 Char 同样为 16 位,取值 0 至 65535,每个码位对应一个 Unicode 字符,默认值为码位 0[1]。
在 C 与 C++ 中,char 是一种用于编码基本执行字符集成员的表示类型,char、signed char 与 unsigned char 被编译器视为互不相同的类型[3]。标准只要求 char 至少 8 位,且满足 1 == sizeof(char) ≤ sizeof(short) ≤ sizeof(int) 的尺寸关系,因此它的实际宽度由实现决定[3]。C 中的 char 究竟是带符号还是无符号同样交由编译器决定,典型取值分别为 -128 至 127 或 0 至 255[4]。
字符类型与字符串类型的区别在于容量:Char 只能保存一个字符,而 String 是零个或多个字符组成的序列,需要存放任意长度文本时应使用后者[5]。字符常量本身也不携带字体信息,只表示单个符号的编码[6]。
原理
字符类型的工作方式是把符号映射为整数码位,再由该整数按位存储。以 Visual Basic 为例,Char 变量中保存的就是 Unicode 字符集的码位,十进制 0 至 127 与 ASCII 定义的码位一致,128 至 255 用于拉丁字母、重音符号、货币符号和分数,其余码位覆盖世界各种文字、变音符号以及数学与技术符号[1]。当用变量保存码位时,关系可以写作 $c = \mathrm{code}(g)$,其中 $g$ 是字符,$c$ 是其码位。
16 位宽度并非对所有字符都够用。Unicode 把 D800 到 DFFF 之间的码位保留给代理对,一个代理对需要用两个 16 位值才能表示单个码位;Char 变量无法容纳代理对,而 String 会用两个位置来保存这类字符[5]。这正是 Java 后来引入码位概念的原因:一个码位可能由一个或两个 16 位 char 组成[7]。
C 与 C++ 的模型则把序列化与内部处理分开:char 用于按字节序列化的字符数据,wchar_t 用于内部处理,两者允许分别对应 UTF-8 与 UTF-32 之类的不同编码形式,但大字符集必须包含小字符集的字符以便相互映射[2]。字符类型与数值类型之间通常需要显式转换,例如用 Asc、AscW 由字符取得码位,用 Chr、ChrW 由码位生成字符[1]。
发展历程
字符编码的标准化始于 20 世纪 60 年代。1961 年,IBM 的 Bob Bemer 向美国国家标准学会提出通用编码方案,ASCII 于 1963 年成为美国标准[8]。该标准采用 7 位二进制数表示 128 个字符,按位模式与字母、数字、标点及控制字符建立对应关系;由于当时传输成本与穿孔纸带的限制,委员会放弃了 8 位方案,选择 7 位编码以便留出校验位[9]。1968 年,美国总统林登·约翰逊要求联邦政府此后采购的计算机支持 ASCII[8]。
字符类型进入语言的时间稍晚。C 由无类型的 B 语言演化而来,B 又源自 BCPL,两者都只有字作为存储单位;在为 PDP-11 重写 Unix 的过程中,char 与 int 作为新类型被加入,分别对应这台机器的字节寻址与字寻址模式[10]。Ritchie 于 1971 年把 char 类型加入 B 语言,C 由此继承,此后 char 的符号性一直保持为实现定义[11]。
多语言需求推动了更宽字符类型的出现。20 世纪 90 年代初 Java 设计时,Unicode 还是固定的 16 位字符集,因此采用 16 位 char 是自然选择;后来 Unicode 扩展为 21 位码位,UCS-2 改为 UTF-16,早期采用 16 位字符的实现被固定下来[12]。C 与 C++ 则在 2011 年的修订中引入固定宽度的 char16_t 和 char32_t,以便无歧义地表示 UTF-16 与 UTF-32,wchar_t 继续保持实现定义[12]。C++20 又新增了用于 UTF-8 表示的 char8_t[3]。
应用
字符类型最直接的用途是保存和处理单个符号,因此字符大小写转换、判断字符是否为字母或数字等操作都以其为输入与输出[13]。C 语言的许多库函数都以 char 为参数类型,例如判断字母的 isalpha 和转小写的 tolower 接收字符并按整数返回结果[14]。
字符串处理同样以字符类型为构件。C 中以 char 数组表示字符串,以 wchar_t 数组表示宽字符串,字符串字面量的类型是 char 数组,而字符字面量的类型是 int[14]。Fortran 的 CHARACTER 类型则提供 1、2、4 字节三种 kind,分别容纳 8 位、16 位与 32 位字符码,便于按不同编码存储文本[15]。
在软件国际化中,字符类型决定了程序能否处理非英语文本。Java 与 C# 的 16 位 char 使程序默认以 UTF-16 处理文本,但外部其他编码的数据必须先转换为 UTF-16 才能使用;这种模型便于可移植程序,代价是需要额外的转换步骤[2]。分类判断也依赖字符类型提供的码位信息,Visual Basic 中可用 IsDigit、IsPunctuation 等方法确定字符的 Unicode 类别[1]。
局限
字符类型最根本的限制是宽度与码位空间不匹配。16 位 char 只能覆盖基本多文种平面,代理对字符必须由两个 char 拼合,按单个 char 遍历字符串就可能把这类字符拆开[5]。C 与 C++ 的情况相反,char 的宽度与符号性都没有统一保证,把字符数据当作算术值或在实现间移植时容易出错[3]。
字符类型还不足以承担语义层面的文本处理。Unicode 联盟指出,由于可移植程序无法确定 C 与 C++ 的 char 或 wchar_t 对应哪个字符集,许多需要字符属性的操作难以直接使用这两个类型[2]。此外,char 只表示单个码位,不包含字体与显示信息,一个字符在屏幕上的呈现需要额外的排版与字体数据[6]。
参数传递层面也存在风险。若数据类型的宽度与编码单元宽度不一致,结果可能不可预测,例如对包含内嵌 NUL 字节的 UTF-16 数据使用面向字节的 strcpy 就会出问题[2]。Visual Basic 文档同样提示,与非 .NET 组件互操作时其他环境的字符类型可能只有 8 位,此时应改用 Byte 而非 Char 传递参数[1]。
参见
参考资料
- Char 数据类型 (Visual Basic) [引用日期2026-10-29]
- 04288-tr17-5d2 [引用日期2026-10-29]
- 内置类型 (C++) - 跳至主要内容 跳到 Ask Learn 聊天体验 [引用日期2026-10-29]
- C关键字和基本类型(括号数字是《从问题到程序》中的章节编号) [引用日期2026-10-29]
- 字元資料類型 (Visual Basic) [引用日期2026-10-29]
- ch08_13 [引用日期2026-10-29]
- 问Java与C中的字符大小EN [引用日期2026-10-29]
- ASCII | Definition, History, Trivia, & Facts | Britannica [引用日期2026-10-29]
- ASCII - The Wayback Machine [引用日期2026-10-29]
- Re: somebody dropped a (warning) bomb [引用日期2026-10-29]
- view-source [引用日期2026-10-29]
- Revision 339a2f23-4465-44f3-8e01-8efbbe2bb5a7 [引用日期2026-10-29]
- [科普中国]-字符数据类型操作 [引用日期2026-10-29]
- RE: string vs. char [was Re: Java and Unicode] [引用日期2026-10-29]
- Implementation of CHARACTER types in f18 [引用日期2026-10-29]