字符类型不止 char 一个:还有明确符号性的 signed char(−128~127)和 unsigned char(0~255),以及装汉字用的宽字符 wchar_t / char16_t / char32_t。核心认知:char 占 1 字节,它到底是有符号还是无符号,由编译器决定(多数是有符号)。所以字节值超过 127 时,按 char 读出来会变成负数——这不是数据坏了,是"解读方式"的选择问题。一个中文汉字在 UTF-8 下占 3 字节,单个 char 装不下。
一、char 家族的四个成员
| 类型 | 字节 | 范围 | 用途 |
|---|---|---|---|
char |
1 | 不确定(看编译器,多半是 −128~127) | 装普通 ASCII 字符 |
signed char |
1 | −128 ~ 127 | 需要"明确有符号"时 |
unsigned char |
1 | 0 ~ 255 | 装原始字节值(如图片、加密数据的字节) |
wchar_t |
Windows 2 / Linux 4 | Unicode 码点 | 宽字符,装汉字等 |
char16_t / char32_t |
2 / 4 | UTF-16 / UTF-32 | C++11 引入,跨平台更规范 |
三个词的区别:
char= "一个字符"(重点在字符)signed char/unsigned char= "一个字节的整数"(重点在数值)wchar_t等 = "一个更宽的字符"(重点在装得下 Unicode)
二、为什么"中文会变成负数"
这是初学者最容易困惑的现象,原因很清楚:
一个字节能表示 0~255。
如果按【无符号】读 → 200 就是 200
如果按【有符号】读 → 200 超过了 127,被解释为 -56
因为 char 多半是"有符号"的,所以当你把"字节值大于 127 的数据"(中文、图片、加密结果)塞进 char 再打印,就会看到负数或乱码。
怎么办:
| 情况 | 用什么 |
|---|---|
| 处理文本(英文、数字符号) | char 没问题 |
| 处理原始字节(二进制数据、编码转换) | unsigned char |
| 处理中文/Unicode 文本 | string(第 6 章)或宽字符 |
一句话判断:你在意"它是哪个字符"就用 char;你在意"它是哪个字节值"就用 unsigned char。
三、编码的层次:为什么需要"宽"字符
| 编码 | 一个汉字占几字节 | 说明 |
|---|---|---|
| ASCII | 装不下 | 只有 0~127,规定的是英文、数字、标点 |
| GBK | 2 | 中文老编码(国内 Windows 常见) |
| UTF-8 | 3 | 现在的主流,兼容 ASCII |
| UTF-16 / UTF-32 | 2 / 4 | 定长,处理起来规整,宽字符用的就是它 |
所以:char 只有 1 字节,装不下一个汉字(UTF-8 要 3 字节);要"一个格子装一个汉字",就需要 2 或 4 字节的宽字符。
你写文件时用 UTF-8 编码保存,读的时候用 GBK 去解——同一个字节序列,按两套规则翻译,出来的就是乱码。"乱码不是数据错了,是两边用的字典不一样"。这也是第一章"Dev-C++ 编码设成 UTF-8"那条设置的意义。
四、动手 Demo:三个实验看清"符号性"
新建 chartype.cpp:
#include <iostream>
using namespace std;
int main() {
cout << "sizeof(char) = " << sizeof(char) << endl; // 1
cout << "sizeof(wchar_t)= " << sizeof(wchar_t)<< endl; // Windows 2
char c = 200; // 超过 127 的字节值
cout << "char 存 200,当整数读 = " << (int)c << endl; // 可能是 -56
unsigned char u = 200;
cout << "unsigned char 存 200 = " << (int)u << endl; // 200
cout << "char 的范围:" << (int)(char)128 << " 起就开始" << endl;
return 0;
}
看到什么算成功:
- char c = 200; 当整数读时变成负数(例如 −56)
- unsigned char u = 200; 老老实实是 200
这就是"符号性"的实际影响——同一串字节,换个类型声明,读出来的数值就变了。
30 秒实验:把 char c = 200; 改成 char c = 'A';,(int)c 输出 65(正常)。说明 ASCII 范围内的字符(0~127)不会受符号性影响——问题只在"字节值大于 127"时出现。
五、常见误区
- "
char就是装字符的,跟数字无关"——它装的就是数字(编码)。所以才会出现"存 200 打印出 −56"这种事 - "中文可以用
char数组存"——语法上可以(char s[] = "中文";就是 3 字节一篇),但每个格子里的值可能显示为负数,且你没法"一个格子对一个汉字"。正式处理中文用string - "
wchar_t是标准 2 字节"——不统一:Windows 上 2 字节(UTF-16),Linux 上通常 4 字节。跨平台要用char16_t/char32_t - "乱码是程序写错了"——多半是编码不一致(写用 UTF-8、读用 GBK)。先怀疑编码设置,再怀疑代码
自测四问(点开对答案)
1. `char` 是几字节?有符号还是无符号?——**1 字节**;**由编译器决定**,多数实现是**有符号**(−128~127)。 2. 为什么 `char c = 200;` 打印出来是负数?——200 超过有符号 `char` 的上限 127,被解释成负数;**要 0~255 请用 `unsigned char`**。 3. 一个汉字在 UTF-8 下占几字节?——**3 字节**,所以单个 `char` 装不下。 4. 乱码通常是为什么?——**编码不一致**:存/读用了不同的编码规则(UTF-8 与 GBK 互读)。- ☑ 布尔类型
相关笔记
- 字符变量 —— 字符的本质是整数
- 字符串常量 —— 一串字符怎么存
- Dev-C++的下载与安装 —— UTF-8 编码设置