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

C 无符号类型转换,并分配给不同字节大小的变量,c,casting,unsigned,signed,C,Casting,Unsigned,Signed,有符号整数被分配给无符号整数。使用不同字节大小的无符号整数时,行为看起来有点奇怪 代码1: #include <stdio.h> typedef unsigned long uint32; typedef unsigned short uint16; typedef signed short sint16; sint16 rawTCU = -100; int main() { uint32 _tm

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

代码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打印

    _tmpSig = 65436

我不明白它的行为如何不同,为什么不同的类型会导致不同的值输出。为什么将uint16用于赋值时会创建不同的值(等于65536-100=65436)。这是如何得到优化的,而不是在使用uint32的过程中。请提供您的建议如何工作。谢谢

当有符号整数类型的负对象被分配(或强制转换)到大小较大的无符号整数类型时,符号位被传播

在这个表达式中

_tmpSig = (uint32)rawTCU;
_tmpSig = (uint16)rawTCU;
rawTCU负值的符号位传播到所有32位

在这个表达式中

_tmpSig = (uint32)rawTCU;
_tmpSig = (uint16)rawTCU;
存在到16位的截断。强制转换的结果被视为无符号值。所以这两种传播都没有发生

注意这个电话

printf("_tmpSig = %d",_tmpSig );
具有未定义的行为。你必须写作

printf("_tmpSig = %lu",_tmpSig );
                  ^^^

这里缺少的是由于向
printf
传递参数时应用的整数提升规则而导致的隐式类型转换

您可能已经注意到,您可以使用相同的格式字符串打印
char
short int
long int
。这是因为
printf
的所有可选参数都经过默认参数升级。事实上,所有变量函数的参数都是如此

促销规则的简化总结如下:

  • 花车变成双倍
  • 小于int的整数类型(即chars和short int)变为int
  • 无符号整数保持为无符号整数
这意味着这里有一个隐藏的转换,这不是很明显,除非你寻找它

案例1:

_tmpSig = (uint32)rawTCU;
这里,由于我们正在从有符号类型转换,因此执行符号扩展,因此
\u tmpSig
成为非常大的无符号数,这是
-100
的表示形式

现在,当调用
printf
时,不会发生升级,因为它已经是
无符号int
。打印时,由于使用了“%d”格式,它将被重新解释为带符号的int,并产生-100

案例2:

_tmpSig = (uint16)rawTCU;
在此之后,
\u tmpSig
现在保存一个无符号短int。此处不需要符号扩展名,因为它被转换为相同大小的类型。因此,代表性根本没有变化

但是,当传递到
printf()
时,它将升级为
带符号的int
。 因此这里有一个从
无符号短
有符号长
的隐藏转换。因为我们正在从无符号类型转换,所以这里没有符号扩展!这就是值实际变为65436的位置。现在,当打印为“%d”时,将打印相同的值


编辑:修复了@EricPostpischil指出的事实错误。如果您的编译器支持它,请使用from
,而不是自己编写。此外,在第一个代码段中,tmpSig是32(或64)位
无符号长
%d”
格式用于有符号的
int
(可能是32位)。这是一个不匹配的格式说明符和参数类型,这会导致未定义的行为。C标准根据涉及的值定义到无符号类型的转换。C实现不会在补码或符号和幅度实现中通过符号扩展进行转换(目前比较深奥)。C标准根据涉及的值定义到无符号类型的转换,而不是符号扩展。C实现不会在补码或符号和幅度实现中通过符号扩展进行转换(目前是深奥的)。Re“打印时,由于使用了“%d”格式,它会转换回带符号的int”:否,不会转换回
int
。根据C标准,标准未定义使用
%d
进行格式化时传递
无符号int
的行为。当一个实现继续进行时,通常会发生的情况是
无符号int
的位被重新解释为
int
@ericppostschil True,而不是转换为
int
。但是我试图解释OP所看到的行为,并且必须假设一个特定的平台。这里采用的许多隐式假设,例如short小于int,可能并不适用于每个C语言实现。关键是调用
printf()
时发生的整数提升,我觉得没有其他答案。@EricPostChil关于你对“%d”的评论,我同意。我将看看是否可以重新表述这一部分,使其更加准确。