类型转换运算符
本节讨论两类“类型转换”:
- 显式转换:强制类型转换 (Cast),由你写在源代码里;
- 隐式转换:由语言规则自动发生(例如算术提升、赋值转换)。
这里重点讨论显式转换(cast 运算符)。
1. C 的 cast 语法
C 的强制类型转换语法是:
c
(type-name) expression1
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
其中 type-name 是类型名,expression 是被转换的表达式。
2. 常见转换类别与标准风险
2.1 整型之间转换
整型转换可能发生截断或符号变化:
c
unsigned char u8 = (unsigned char)1000; /* 结果与实现的 unsigned char 宽度有关 */1
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
2.2 指针转换与对齐
本章不讨论指针相关的转换。相关规则将在后续章节中系统介绍。
2.3 浮点与整型互转
浮点转整型时,如果值超出目标整型可表示范围,行为未定义;此外,小数部分会被舍弃(向零取整)。
3. 实践建议
- 把 cast 当作“在类型系统里打洞”:写下 cast 的同时,应当能解释“为什么此处合法”。
- 不要用 cast 掩盖编译器警告:警告往往是在提示你“可能违反标准规则”。
4. void* 转换边界
对象指针在 void* 之间的往返转换是 C 里常见能力,但前提是“转回原始对象类型”再使用。若转成不兼容类型后直接解引用,行为就不再有保障。
c
int x = 42;
void *vp = &x;
int *ip = (int *)vp; /* 转回原类型 */1
2
3
2
3
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
这个模式常用于通用容器和回调接口,但转换点应尽量集中、可审计。
5. 显式转换应服务于接口边界
多数显式转换都发生在接口边界:解析文本到数值、通用指针回收到具体类型、跨模块约定统一宽度。若一个模块内部频繁出现 cast,通常意味着类型设计还有优化空间。把转换点收敛到边界位置,不仅更易审查,也能减少语义漂移。
6. 习题
#10416
⚡5⏳3
写一个程序,读入一个 double,并把它转换成 int 输出。要求:
- 解释小数部分如何处理;
- 讨论当输入值超出
int表示范围时会发生什么(标准层面)。
#10417
⚡7⏳4
阅读并判断:下面的强制类型转换在标准层面可能带来哪些风险?(提示:范围、精度、未定义行为)
c
double x = 1e100;
int y = (int)x;1
2
2
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。