在项目中遇到一个奇怪的问题,伪代码如下:
int8_t a = 0x8F;uint8_t b = 0x8F;if( a == b ){ printf("a = b\n");}else{ printf("a != b, a = %02x, b = %02x\n", a, b);}
按照我的理解,if(a == b)
一定为真。但运行结果却让我大跌眼镜:
a != b, a = ffffff8f, b = 8F
首先,变量a
不等于b
已经让我吃惊了,然后,打印出来a
的值竟然是ffffff8f
!查了一通资料,我才知道,原来在 C 语言中有隐式类型转换
这么一个规则。隐式类型转换
是指变量在运算中的一种隐式的类型转换,主要分两种:算术
和赋值
转换。
算术转换
算术转换的规则可以用一张图来表示:
HIGH ^double <-- float |long |unsigned |int <-- char, short ^LOW
此图中有两个箭头。
竖向箭头表示不同的数据类型在进行混合运算的时候,会有一个低字节向高字节转换的过程。术语叫寻常算术转换
(usual arithmetic conversion
)。
横向箭头表示不管该类型有没有进行混合运算都势必会进行转换,再进行运算,术语叫整型提升
(Integral promotions
)。
赋值转换
进行赋值操作时,赋值运算符右边的数据类型必须转换成赋值号左边的类型,若右边的数据类型的长度大于左边,则要进行求余的截取操作。
如定义变量uint8_t a = 257;
,因为uint8_t
类型的最大值是256
,所以要求余的截取操作,最终a = 257 % 256 = 1
。
又如:
int8_t a = -1;int32_t b = a;printf("a = %x, b = %x\n",a, b);
这就是一个扩展操作,a
先被转为int
,再被转为unsigned
,b
的十六进制值等于0xFFFFFFFF
。
回到最开始的那个问题,在==
运算中,a
和b
都被隐式地转换成了int
型,一个是-113
,一个是143
,肯定不一样。
prinf
的参数实际上也是一种赋值转换,因为%02x
指定了参数的类型是uint32_t
,所以a
被隐式地转换为了uint32_t
的类型,也即0xfffffff8
。
参考:
整型提升
C的隐式类型转换
关于C语言的隐式类型转换
悠然享受和大自然融合之乐。