【问题标题】:Unexpected results on difference of unsigned ints无符号整数差异的意外结果
【发布时间】:2014-11-18 02:38:11
【问题描述】:

我很惊讶这个函数会为 dif1 和 dif2 产生不同的值

void test()
{
    unsigned int x = 0, y = 1;
    long long dif1 = x - y;
    long long dif2 = (int)(x - y);
    printf("dif = %lld %lld",dif1,dif2);
}

这是正确的行为吗?在 diff1 计算中,它首先将 32 位无符号差异提升为 64 位无符号值,然后添加符号。这是语言未指定的标准行为还是编译器错误?第二种形式是否保证产生-1,或者直到编译器实现?我想最安全的结构是: long long diff3 = (long long)x - (long long)y;

【问题讨论】:

    标签: c


    【解决方案1】:

    如果我们假设long longunsigned int 宽,第一个是明确定义的。如果不是,那么作业给出的问题与答案的第二部分相同。

    long long dif1 = x - y;
    

    无符号整数会换行,你会得到一个可以存储在无符号整数中的最大值。

    6.2.5 p9:涉及无符号操作数的计算永远不会溢出, 因为不能用生成的无符号整数类型表示的结果是 以比最大值大一的数字为模减少,可以是 由结果类型表示。


    至于第二个

    long long dif2 = (int)(x - y);
    

    它是实现定义的:

    6.3.1.3 p3:否则,新类型有符号,值不能在其中表示;无论是 结果是实现定义的或引发了实现定义的信号。

    在这种情况下,unsigned int 的最大值不能在 int 中表示,上述规则有效。

    【讨论】:

    • 我想当 y 大于 x 时 int dif = x - y 也是实现定义的情况。所以,除非你想要无符号的模结果,否则你真的不应该取无符号整数的差。
    • 我猜这也意味着当 x 和 y 是无符号整数时,abs(x-y) 不一定等于 abs(y-x)。
    【解决方案2】:

    这没什么好奇怪的。

    unsigned int x = 0, y = 1;
    long long dif1 = x - y;
    long long dif2 = (int)(x - y);
    

    第二个和第一个有一个不同:

    signed.
    如果可能,强制转换被定义为保值(不可能,因为UINT_MAX 大于INT_MAX),否则实现定义(尽管允许陷阱)。

    如果我们有 2s-complement 进行转换(很可能),则转换结果为 -1

    接下来,我们有一个更广泛的有符号类型的赋值,它始终是保值的。

    【讨论】:

    • 我认为在对有符号值 dif1 的赋值中存在对“有符号”的隐式强制转换。但是,显然尺寸扩展首先发生。即,dif1 = (signed) ((unsigned long long) (x - y))
    猜你喜欢
    • 1970-01-01
    • 2014-07-14
    • 1970-01-01
    • 1970-01-01
    • 2016-03-27
    • 1970-01-01
    • 2018-12-17
    • 2012-02-11
    • 2017-06-05
    相关资源
    最近更新 更多