C 具有负股息和除数的模运算差异是长无符号的

C Modulo operation differences with negative dividend and divisor is long unsigned

你好,我知道 C 负股息的 modulo 会导致负模数,但我发现负股息的模数使用长无符号除数或long long unsigned 除数会产生正模!

这是一个例子:

#include <stdio.h>

int main(int argc, char** argv)
{
    long long int a = -2205348223670655684LL;
    printf("%lld %lld %lld %lld %lld %lld\n", a % 20, a % 20L, a % 20LL, a % 20U, a % 20LU, a % 20LLU);
    return 0;
}

和输出:

$> ./a.out
-4 -4 -4 -4 12 12

谁能解释一下为什么?我用 GCC 4.8 和 5.1

试过了

C99 第 6.5.5/6 节要求当 a/b 可表示时:

(a/b) * b + a%b shall equal a

从 6.5.5/3

The usual arithmetic conversions are performed on the operands.

算术转换的更多细节,请查看6.3.1.8小节

现在你的实现似乎是这样sizeof(long) = sizeof(long long) = 64 bits

对于前 4 种情况,有符号或无符号除数可以更改为分子类型(即 long long int),但在后 2 种情况下,股息必须更改(转换或重新解释为)为无符号类型作为除数具有相同的宽度并且没有符号导致结果。

在某些 sizeof(long) < sizoef(long long) 的系统上,倒数第二个结果应该不同。

不存在使用一个有符号和一个无符号操作数执行的(内置)算术运算;二元运算的两个操作数都提升为相同类型。

在你最后两个例子中,那个类型是unsigned long long;所以 a 被转换为无符号值,余数是使用它计算的。