char符号性由编译器决定,非天然有符号;int和long大小跨平台不一致;浮点数需避免直接比较和过度打印精度。

char 是 1 字节,但 signed 还是 unsigned 取决于编译器
很多初学者以为 char 天然就是有符号的,结果在嵌入式或不同平台(比如 ARM vs x86)上读到负值,发现 printf("%d", c) 输出 -1 而不是 255。这是因为 C 标准只规定 char 占 1 字节,但没规定默认符号性——它可能是 signed char,也可能是 unsigned char,由编译器实现决定。
实操建议:
立即学习“C语言免费学习笔记(深入)”;
- 需要明确范围时,别用裸
char存整数,直接写signed char或unsigned char - 用
%hhd打印signed char,%hhu打印unsigned char;混用%d会触发整型提升,掩盖底层类型问题 - 检查当前平台行为:编译时加
-fsigned-char或-funsigned-char强制统一,尤其做跨平台通信或协议解析时
int 不一定是 4 字节,long 在 Windows 和 Linux 上表现不同
int 的大小只保证 ≥ short 且 ≤ long,实际常见为 2 或 4 字节(16 位单片机 vs 普通 PC)。更麻烦的是 long:在 Windows x64 上仍是 4 字节(LLP64),而 Linux x64 是 8 字节(LP64)。这意味着用 %ld 打印一个 long 值,在两个系统上可能截断或读错内存。
实操建议:
立即学习“C语言免费学习笔记(深入)”;
- 不要假设
int是 4 字节;需要固定宽度时,用int32_t、uint64_t(需#include <stdint.h></stdint.h>) - 打印固定宽度类型,必须配对使用
PRIu32、PRId64等宏(来自<inttypes.h></inttypes.h>),而不是硬写%d或%ld - 结构体中混用
int和long时,注意填充差异——同一结构体在 MinGW 和 GCC 下sizeof可能不同
float 和 double 的精度陷阱藏在 printf 和比较里
float 通常 4 字节、约 7 位十进制精度;double 通常 8 字节、约 15 位。但很多人用 printf("%f", f) 看 float 值,发现输出一长串小数,误以为“精度高”,其实只是把二进制近似值无意义地展开。更危险的是用 == 比较浮点数,比如 0.1f + 0.2f == 0.3f 在大多数平台返回 0。
实操建议:
立即学习“C语言免费学习笔记(深入)”;
- 打印浮点数时限制小数位:
printf("%.6f", x)(float)或printf("%.15g", y)(double),避免误导 - 比较用误差范围:
fabs(a - b) ,而不是 <code>a == b - 计算中间结果优先用
double,尤其涉及累加、开方等易放大误差的操作;float仅用于显存/带宽受限场景(如 GPU shader、传感器原始数据缓存)
格式说明符和变量类型不匹配会导致未定义行为
这是最隐蔽也最常踩的坑:printf("%d", (short)123) 看似没问题,但 short 传参时自动提升为 int,所以这里侥幸成立;而 printf("%d", (char)200) 在 char 是 signed 的平台会传入 -56,再按 %d 解释就错乱了。更严重的是 printf("%s", ptr) 中 ptr 为 NULL,或 %x 对应传了 char*,直接触发未定义行为(UB),调试器都可能不报错。
实操建议:
立即学习“C语言免费学习笔记(深入)”;
- 开启编译警告:
-Wall -Wformat -Wformat-security,GCC/Clang 能捕获大部分说明符-参数不匹配 - 指针一律用
%p,且传入前强转为void*:printf("%p", (void*)ptr) - 自定义类型(如
typedef uint32_t my_id_t)打印时,别想当然用%u,先查 typedef 展开后的真实类型,再选对应说明符或PRIu32
字节数只是表象,真正要盯住的是 ABI 规则、整型提升时机、以及格式化 I/O 如何解释栈上传来的原始比特——这些地方松一寸,运行时就偏一丈。










