C语言 具有无符号的类型转换,并分配给不同字节大小的变量



>有符号整数被分配给一个无符号整数。使用不同字节大小的无符号整数时,行为看起来有点奇怪。

代码 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">打印charshort intlong 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 shortsigned long的隐藏转换.由于我们正在从无符号类型转换,因此此处没有符号扩展!这就是值实际变为65436的地方。现在,在打印为"%d"时,将打印相同的值。

编辑:修复了@EricPostpischil指出的事实不准确

相关内容

  • 没有找到相关文章

最新更新