>有符号整数被分配给一个无符号整数。使用不同字节大小的无符号整数时,行为看起来有点奇怪。
代码 1:
#include <stdio.h>
typedef unsigned long uint32;
typedef unsigned short uint16;
typedef signed short sint16;
sint16 rawTCU = -100;
int main()
{
uint32 _tmpSig = 0;
_tmpSig = (uint32)rawTCU;
printf("_tmpSig = %d",_tmpSig );
return 0;
}
代码 2:
#include <stdio.h>
typedef unsigned long uint32;
typedef unsigned short uint16;
typedef signed short sint16;
sint16 rawTCU = -100;
int main()
{
uint16 _tmpSig = 0;
_tmpSig = (uint16)rawTCU;
printf("_tmpSig = %d",_tmpSig );
return 0;
}
代码 1 打印
_tmpSig = -100
代码 2 打印
_tmpSig = 65436
我不明白它的行为有何不同,为什么不同类型的会导致不同的值输出。为什么当使用 uint16 进行赋值时,它会创建一个不同的值(等于 65536 - 100 = 65436(。如何优化,但不是在使用 uint32 期间。请提供您的建议,其工作原理。谢谢!
当有符号整数类型的负对象被赋值(或强制转换(给具有较大大小的无符号整数类型时,符号位将被传播。
在此表达式中
_tmpSig = (uint32)rawTCU;
rawTCU 负值的符号位传播到所有 32 位。
在此表达式中
_tmpSig = (uint16)rawTCU;
截断为 16 位。强制转换的结果被视为无符号值。因此,这两种传播都不会发生。
注意这个电话
printf("_tmpSig = %d",_tmpSig );
具有未定义的行为。你必须写
printf("_tmpSig = %lu",_tmpSig );
^^^
您在这里缺少的是隐式类型转换,这是由于在将参数传递给printf
时应用的整数提升规则。
您可能已经注意到,您可以使用相同的格式字符串"%d">打印char
、short int
或long int
。这是因为printf
的所有可选参数都经过默认参数提升。事实上,所有可变参数函数的参数都是如此!
对促销规则的简化总结如下:
- 浮子变成双倍 小于 int 的整数
- 类型(即字符和短整数(变为 int 无符号 int
- 仍为无符号 int
这意味着这里有一个隐藏的转换,除非你寻找它,否则这不是很明显。
案例1:
_tmpSig = (uint32)rawTCU;
在这里,由于我们正在从有符号类型转换,因此执行符号扩展_tmpSig
因此它成为一个非常大的无符号数字,这是-100
的表示。
现在,当调用printf
时,不会发生任何促销,因为它已经是一个unsigned int
。打印时,由于使用了"%d"格式,因此会将其重新解释为signed int
并生成 -100。
案例2:
_tmpSig = (uint16)rawTCU;
在此之后,_tmpSig
现在持有一个无符号的短整型。 此处不需要符号扩展,因为它被转换为相同大小的类型。所以表示形式根本没有变化。
但是,当传递给printf()
时,它被提升为signed int
。 所以这里有一个从unsigned short
到signed long
的隐藏转换.由于我们正在从无符号类型转换,因此此处没有符号扩展!这就是值实际变为65436的地方。现在,在打印为"%d"时,将打印相同的值。
编辑:修复了@EricPostpischil指出的事实不准确