3. 基本数据类型(下):浮点型、字符型、布尔型与sizeof

好,咱们接着聊。上一节我们把整数型聊透了,这一节我带你看看剩下的几个“常客”——浮点型、字符型、还有那个很多人容易忽略的布尔型。最后,我会教你一个特别实用的工具:sizeof

说实话,我当年刚学C语言时,觉得浮点数不就是带小数点的数嘛,有啥好讲的?结果第一次做嵌入式项目,就被精度问题坑了一把。嗯,咱们慢慢说。

3.1 浮点型:float 与 double

浮点型,说白了就是用来存小数的。C语言里主要有两种:floatdouble

类型 字节数 有效位数 典型范围
float 4 字节 约 6~7 位 ±1.2e-38 ~ ±3.4e38
double 8 字节 约 15~16 位 ±2.2e-308 ~ ±1.8e308

你可能会问:为什么叫“浮点”?因为小数点可以浮动。比如 3.14 和 314.0,在内存里其实是用科学计数法存的,指数部分决定了小数点的位置。

核心区别:float 省内存,但精度低;double 精度高,但占空间。在单片机上,我一般优先用 float,除非对精度有硬性要求。

举个例子:

float pi = 3.14159f;      // 注意后面的 f,表示 float 字面量
double pi_d = 3.141592653589793;

这里有个细节:如果你写 3.14159 不加 f,编译器默认它是 double 类型。赋值给 float 时会有隐式转换,虽然大多数情况没问题,但我建议你养成加 f 的习惯。

注意:浮点数不能直接用 == 比较相等!因为精度问题,0.1 + 0.2 可能不等于 0.3。我曾经在项目里用 if (a == b) 判断两个浮点数,结果程序时灵时不灵,查了一天才发现是精度问题。正确的做法是判断差值是否小于某个很小的数,比如 fabs(a - b) < 1e-6

3.2 字符型:char

字符型 char 在 C 语言里其实是个“两面派”。它本质上是一个整数,但通常用来表示字符。

你看:

char ch = 'A';        // 字符 A
char code = 65;       // 也是 A,因为 ASCII 码中 65 对应 'A'

这两行代码效果完全一样。为什么?因为 char 就是 1 字节的整数,范围 -128 到 127(如果是有符号),或者 0 到 255(如果是无符号)。

我个人习惯用 char 存字符,用 unsigned char 存小范围整数或原始字节数据。比如在通信协议里,我经常用 unsigned char 来存接收到的数据包。

小技巧:如果你不确定 char 在某个平台上是有符号还是无符号,可以用 char c = 0xFF; if (c > 0) ... 来测试。不过更稳妥的做法是显式声明 signed charunsigned char

3.3 布尔型:_Bool

C99 标准引入了 _Bool 类型,专门用来表示真/假。它只有两个值:0 表示假,非 0 表示真。

不过说实话,_Bool 这个名字有点丑。所以标准库提供了 stdbool.h,里面定义了 booltruefalse 三个宏。我建议你直接用这个:

#include <stdbool.h>

bool is_ready = true;
if (is_ready) {
    // 执行操作
}

你想想看,用 bool 比用 int flag = 1 要清晰得多。代码的可读性一下子就上来了。

注意:_Bool 其实只占 1 字节,但如果你把它放在结构体里,可能会因为对齐产生额外的空间开销。我在做嵌入式开发时,如果内存特别紧张,有时会用 unsigned int 的某一位来存布尔值,但那是极端情况了。

3.4 数据类型的大小:sizeof

sizeof 是 C 语言的一个运算符,不是函数。它用来计算某个类型或变量占用的字节数。

用法很简单:

printf("int 的大小: %zu 字节\n", sizeof(int));
printf("float 的大小: %zu 字节\n", sizeof(float));

int arr[10];
printf("数组大小: %zu 字节\n", sizeof(arr));   // 40 字节(假设 int 占 4 字节)

这里有个坑:sizeof 对数组名求值时,得到的是整个数组的大小,而不是指针的大小。但如果你把数组名传给函数,它就退化为指针了,这时候 sizeof 得到的是指针的大小。

我曾经踩过的坑:写了一个函数,参数是 int arr[],然后在函数里用 sizeof(arr) / sizeof(arr[0]) 来算数组长度。结果死活不对。后来才意识到,函数参数里的 int arr[] 其实就是 int *arrsizeof(arr) 返回的是指针大小(4 或 8 字节),而不是数组大小。所以,数组长度最好在外面算好再传进来。

另外,sizeof 的结果类型是 size_t,用 %zu 格式化输出。有些老编译器可能不支持 %zu,那就用 %lu 或强制类型转换。

3.5 知识体系总览

下面这张图帮你梳理一下这一节的核心内容:

基本数据类型(下) 浮点型 float / double 精度不同,占空间不同 字符型 char 本质是1字节整数 布尔型 _Bool / bool 真/假,0或非0 sizeof 计算字节数 运算符,非函数 核心要点 • float 加 f 后缀,double 不加 • 浮点数不要用 == 比较 • char 本质是整数,注意有符号/无符号 • sizeof 对数组和指针行为不同,小心踩坑

3.6 小结

这一节我们聊了浮点型、字符型、布尔型,还有那个看似简单但容易出错的 sizeof。说白了,这些类型都是你写 C 程序时天天要打交道的。理解它们的本质——浮点数是科学计数法,字符数是整数,布尔数就是 0 或非 0——你就能避免很多低级错误。

嗯,我记得刚入行时,带我的老工程师跟我说过一句话:“C 语言的数据类型,就像工具箱里的螺丝刀。你得知道哪个是十字的,哪个是一字的,用错了就会滑丝。” 这么多年过去了,我觉得这话一点没错。


公众号:蓝海资料掘金营,微信deep3321