【问题标题】:What type-conversions are happening?发生了哪些类型转换?
【发布时间】:2011-04-16 08:18:23
【问题描述】:
#include "stdio.h"

int main()
{
    int x = -13701;
    unsigned int y = 3;
    signed short z = x / y;

    printf("z = %d\n", z);

    return 0;
}

我希望答案是 -4567。我得到“z = 17278”。 为什么提升这些数字会导致 17278?

我在Code Pad 中执行了这个。

【问题讨论】:

    标签: c type-conversion promotions


    【解决方案1】:

    简答:该部门首先将x 提升为unsigned。只有这样,结果才会被转换回signed short。

    长答案:阅读this SO thread.

    【讨论】:

      【解决方案2】:

      问题来自unsigned int y。事实上,x/y 变成了无符号的。它适用于:

      #include "stdio.h"
      
      int main()
      {
          int x = -13701;
          signed int y = 3;
          signed short z = x / y;
      
          printf("z = %d\n", z);
      
          return 0;
      }
      

      【讨论】:

        【解决方案3】:

        隐藏的类型转换是:

        signed short z = (signed short) (((unsigned int) x) / y);
        

        当您混合有符号和无符号类型时,无符号类型会获胜。 x 转换为 unsigned int,除以 3,然后将结果向下转换为(有符号)short。使用 32 位整数:

        (unsigned) -13701         == (unsigned) 0xFFFFCA7B // Bit pattern
        (unsigned) 0xFFFFCA7B     == (unsigned) 4294953595 // Re-interpret as unsigned
        (unsigned) 4294953595 / 3 == (unsigned) 1431651198 // Divide by 3
        (unsigned) 1431651198     == (unsigned) 0x5555437E // Bit pattern of that result
        (short) 0x5555437E        == (short) 0x437E        // Strip high 16 bits
        (short) 0x437E            == (short) 17278         // Re-interpret as short
        

        顺便说一句,signed 关键字是不必要的。 signed short 是 short 的更长表达方式。唯一需要显式signed 的类型是char。 char 可以根据平台签名或不签名;所有其他类型始终默认签名。

        【讨论】:

        • 值得注意的是,一般情况下,有符号到无符号的转换不是基于重新解释的。事实上,转换和重新解释是非常、非常、非常不同的东西,而我们在这种情况下所拥有的实际上是转换,而不是重新解释。
        • @AnT 你是什么意思?在我看来,有符号 无符号强制转换完全是重新解释,因为内存中的位不会改变,只会改变它们所代表的以 10 为底的整数。另一方面,int 短转换实际上可能会改变位,因此它们不是简单的重新解释。
        • @Aditya Kashi:在现代硬件平台上,签名和未签名之间的转换纯粹是概念(“不要更​​改内存”),因为这些平台使用 2's-有符号值的补充表示。最初的 C 和 C++ 标准不强制要求 2 的补码表示,但也支持 1 的补码 表示和 有符号幅度 表示。在这些替代的有符号表示中,转换不再是概念性的。它改变值的表示,意味着转换和重新解释产生不同的结果。
        • 最新版本的语言标准决定放弃对 1 的补码和有符号量级的支持,因此现在您可以相当安全地假设有符号和无符号之间的转换“没有任何改变”。
        【解决方案4】:

        每次在加法和乘法算术运算中混合“大”有符号和无符号值时,无符号类型“获胜”并且在无符号类型的域中执行评估(“大”表示 int 和更大)。如果你原来的有符号值是负数,它首先会按照有符号到无符号转换的规则转换为正无符号值。在您的情况下,-13701 将变为 UINT_MAX + 1 - 13701,结果将用作股息。

        请注意,典型 32 位 int 平台上的有符号到无符号转换的结果将产生无符号值 4294953595。除以3 后,您将得到1431651198。此值太大,无法在 16 位 short 类型的平台上强制转换为 short 对象。尝试这样做会导致实现定义的行为。因此,如果您的平台属性与我的假设相同,那么您的代码会产生实现定义的行为。正式地说,你得到的“无意义”17278 值只不过是实现定义的行为的具体表现。如果您在编译代码时启用了溢出检查(如果您的编译器支持它们),那么它可能会陷入分配问题。

        【讨论】:

        • 实际上,这不是未定义的行为:标准规定结果是实现定义的,或者引发了实现定义的信号(转换为更窄的有符号类型与计算期间的溢出不同)。
        • @caf:你说的很对。感谢您的更正。嗯...我记得自己多次纠正过这个评论,但在这种情况下,我不知何故忘记了这一切:)
        猜你喜欢
        • 2011-08-24
        • 1970-01-01
        • 2013-06-05
        • 2013-03-23
        • 2021-06-22
        • 1970-01-01
        • 1970-01-01
        • 2021-02-13
        • 1970-01-01
        相关资源
        最近更新 更多