2012-01-19 15 views
5

私が書いた一部のCコードにバグがありましたが、修正するのは比較的簡単でしたが、より良い問題の原因を理解できるようにしたいと考えています。基本的に何が起こったのですか?モジュラス演算が適用されたときに、負の数の符号なし等価、ラップされた数が「大きい」という2つの符号なし整数(実際はuint32_t)があります。ここで実証するプログラム例です:Cのモジュラス演算子で符号なしオーバーフローが発生しました

#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つの符号なし数値の間のモジュラス演算は、なぜ除数(つまり負の数)より大きい数値を生成するのですか?この動作が好まれる理由はありますか?

+1

2600000000はint型(int型long型またはlong型のlong型)なので、乗算の結果が(signed)longになる可能性があります。あなたはどんなプラットフォームですか? – Random832

答えて

3

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

+2

実際にOPは間違ったフォーマット文字列を 'printf'に渡すことによってUBを呼び出しました。 –

2

私は参考になっていませんが、その乗算を行うとint64_tに昇格します.2つの被乗数を符号付き整数型に強制する必要があるためです。 2600000000u代わりの2600000000 ....

関連する問題