5

私が書いたいくつかの C コードでバグが発生しました。修正は比較的簡単でしたが、その根底にある問題をよりよく理解したいと考えています。基本的に何が起こったのかというと、2 つの符号なし整数 (実際には uint32_t) があり、モジュラス演算が適用されたときに、負の数に相当する符号なしの数値、つまりラップされたために「大きい」数値が得られました。以下は、デモ用のプログラム例です。

#include <stdio.h>
#include <stdint.h>

int main(int argc, char* argv[]) {

  uint32_t foo = -1;
  uint32_t u   = 2048;
  uint64_t ul  = 2048;

  fprintf(stderr, "%d\n", foo);
  fprintf(stderr, "%u\n", foo);
  fprintf(stderr, "%lu\n", ((foo * 2600000000) % u));
  fprintf(stderr, "%ld\n", ((foo * 2600000000) % u));
  fprintf(stderr, "%lu\n", ((foo * 2600000000) % ul));
  fprintf(stderr, "%lu\n", foo % ul);

  return 0;

}

これにより、x86_64 マシンで次の出力が生成されます。

-1
4294967295
18446744073709551104
-512
1536
2047

1536 は私が期待していた数値ですが、(uint32_t)(-512) は私が取得していた数値です。

だから、私の質問はこれだと思います: この場合、2 つの符号なし数値間のモジュラス演算は、除数よりも大きい数値 (つまり、負の数値) を生成するのはなぜですか? この動作が好まれる理由はありますか?

4

2 に答える 2

3

2600000000その理由は、コンパイラがリテラルを符号付き 32 ビット int に適合しないため、符号付き 64 ビット数値として解釈しているためだと思います。数字を に置き換えると2600000000U、期待どおりの結果が得られるはずです。

于 2012-01-19T20:18:22.190 に答える
2

便利な参照はありませんが、その乗算を行うとint64_t、2 つの被乗数を符号付き整数型に強制する必要があるため、それらが に昇格されると確信しています。...2600000000uの代わりに試してください。2600000000

于 2012-01-19T20:17:38.133 に答える