笔记:从’FATE’深入理解C语言字符与整数

Aerhuo 发布于 24 天前 41 次阅读


一、 核心前提:char是特殊的int

在C语言中,char类型本质上是一个小型整数,它存储的是字符对应的ASCII码。然而,一个单独的字符字面量(如'B')在表达式中会被 提升(promoted)int类型。

举例:
一个char变量像一个小盒子,只能装1个字节的东西。但'B'这个字面量本身,在被使用时,计算机会暂时把它放进一个标准大小的int盒子(通常4字节)里处理。

#include <stdio.h>

int main() {
    char grade_char = 'B'; // 'B' (值66) 被存入1字节的变量中

    // sizeof('B') 会显示 int 的大小
    printf("字面量 'B' 在表达式中的大小: %zu 字节\n", sizeof('B'));

    // sizeof(grade_char) 会显示 char 的大小
    printf("char 变量 grade_char 的大小: %zu 字节\n", sizeof(grade_char));
}
// 输出:
// 字面量 'B' 在表达式中的大小: 4
// char 变量 grade_char 的大小: 1

二、 多字节字符常量:一个int里的“俄罗斯套娃”

C语言允许一个“魔术操作”:将多个字符塞进一对单引号里,形成一个多字节字符常量,它的类型是int

举例:'FATE'
这相当于把4个独立的8位char(F, A, T, E)打包进了一个32位的int中。

  • 值的构成:它的整数值是由每个字符的ASCII码通过位运算组合而成,具体值是实现定义的(取决于编译器)。在GCC/Clang等常见编译器上,其值的十六进制表示为0x46415445,十进制为1,178,686,533
    • 'F' -> 0x46
    • 'A' -> 0x41
    • 'T' -> 0x54
    • 'E' -> 0x45
#include <stdio.h>

int main() {
    int fate_value = 'FATE';

    // 使用 %X 格式化输出十六进制,可以清晰看到拼接结构
    printf("'FATE' 的十六进制值: 0x%X\n", fate_value);
    printf("'FATE' 的十进制值: %d\n", fate_value);
}
// 输出:
// 'FATE' 的十六进制值: 0x46415445
// 'FATE' 的十进制值: 1178686533

三、 截断:当int遇到char

当一个大的数据类型(如32位的int)被赋值给一个小的类型(如8位的char)时,会发生截断

举例:
这就像把一个大水桶(int)里的水倒进一个小水杯(char)里,只有最底下的那部分水能装进去。对于数字,保留的是最低有效字节 (Least Significant Byte, LSB)

#include <stdio.h>

int main() {
    // 'FATE' 的值是 0x46415445
    // 最低有效字节是 0x45, 也就是 'E' 的 ASCII 码
    char grade = 'FATE';

    printf("当 'FATE' 赋值给 char 时,结果是: %c\n", grade);
    printf("对应的 ASCII 码是: %d\n", grade);
}
// 输出:
// 当 'FATE' 赋值给 char 时,结果是: E
// 对应的 ASCII 码是: 69

四、 物理存储与字节序 (Endianness)

字节序规定了一个多字节数据在内存中的物理排列顺序

  • 二进制是根本:计算机只懂二进制。十六进制是方便人类读写二进制的“简写”。
  • 小端序 (Little-Endian)最低有效字节存储在最低的内存地址。(主流PC为此模式)
  • 大端序 (Big-Endian)最高有效字节存储在最高的内存地址。

举例:int fate_int = 'FATE'; 在小端序机器上的内存布局
fate_int的值为0x46415445,它在内存中的4个字节内容会是:

内存地址 N N+1 N+2 N+3
存放内容 0x45 ('E') 0x54 ('T') 0x41 ('A') 0x46 ('F')

五、 长度限制与合法性

多字节字符常量并非无限长,它受到int类型大小的物理限制。

  • 情况1:正好 (≤ 4 字符)
    int val = 'FATE'; -> 合法,值由4个字符构成。

  • 情况2:略长 (> 4 字符)
    int val = 'ABCDE'; -> 通常会收到编译器警告,并发生截断,只取最后的4个字符 'BCDE' 来计算值。

  • 情况3:过长 (>> 4 字符)
    int val = 'FSFIJHISJFHIOHIJJIO'; -> 这是一个不合法的字面量,因为它在物理上无法被存入一个int。编译器会直接报错