C99注86中“强制转换指定转换”含义及对表达式的影响问询
咱们一步一步拆解这个问题,先搞懂cast specifies a conversion到底说的是什么,再分析它对你给出的代码的实际影响。
先解读标准中的规则
首先来看你引用的C99标准内容:
在C 1999注86(对应6.5.4第5款,以下为加粗内容):若表达式的值的表示精度或范围大于强制转换指定类型所需的精度或范围(6.3.1.8),则即使表达式类型与指定类型相同,该强制转换仍指定一个转换。
这句话的核心意思是:强制转换的作用不只是“改变静态类型”,而是只要原表达式的值的实际表示精度/范围超过了目标类型的要求,哪怕表达式的静态类型和目标类型完全一致,这个强制转换依然会触发一个实际的转换操作。
这里的关键点是区分「表达式的静态类型」和「表达式值的实际表示精度/范围」:静态类型是你写代码时声明的类型,但在表达式求值过程中,C会自动做算术提升(比如char、short会被提升为int),这时候表达式的值的实际精度是提升后的类型(比如32位int),而非原变量的静态类型(比如8位char)。
分析你的示例代码
先看你给出的代码:
signed char a = -2; unsigned char b = 1; b = (short)a + (short)b; b = (short)a + (short)b;
第一步:拆解(short)a和(short)b的转换过程
如果没有强制转换,根据C的常规算术提升规则:
a(signed char)和b(unsigned char)都会被自动提升为int(假设你的平台上int是32位,short是16位),此时它们的值的精度是32位,远大于short的16位。
当你加上(short)强制转换后:
- 编译器先执行自动提升:
a变成32位int值-2,b变成32位int值1 - 然后执行强制转换:把32位的int值转成16位的short值——这完全符合标准中“表达式的值的表示精度大于强制转换指定类型”的情况,所以这个强制转换是实际生效的转换操作,不是冗余的语法。
第二步:分析整个表达式b = (short)a + (short)b的执行流程
你的初步理解是对的,强制转换的优先级高于加法运算符+,所以执行顺序是:
- 对
a做强制转换:(short)a得到16位short值-2 - 对
b做强制转换:(short)b得到16位short值1 - 对两个short操作数执行常规算术转换:由于int的精度足够覆盖short的所有可能值,所以两个short会被再次提升为int,然后执行加法,得到32位int值
-1 - 最后把int值
-1赋值给b(unsigned char):此时会触发隐式转换,把有符号的-1转成无符号的unsigned char,结果是UCHAR_MAX(比如8位平台上的255)
解答你困惑的那句话
你疑惑的“即使表达式类型与指定类型相同,该强制转换仍指定一个转换”,其实是标准在覆盖一种特殊场景:比如某个表达式的静态类型已经是short,但它的值的实际表示精度是更大的类型(比如在求值时用32位寄存器存储这个16位short值),这时候你写(short)e(e是short类型),虽然类型相同,但由于值的实际表示精度超过了short的要求,这个强制转换依然会执行转换操作(比如把32位的存储截断成16位)。
不过在你的示例代码里,(short)a和(short)b的表达式静态类型(signed char/unsigned char)和目标类型(short)不同,所以主要是前面说的“提升后精度大于目标类型”的情况触发了转换。
内容的提问来源于stack exchange,提问作者op ol

