2012-01-19 15 views
5

napotkałem błąd w jakimś kodzie napisanym przeze mnie, i chociaż było to stosunkowo łatwe do naprawienia, chcę być w stanie lepiej zrozumieć problem leżący u jego podstaw. w zasadzie to, co się stało, miałem dwie niepisane liczby całkowite (w rzeczywistości uint32_t), że po zastosowaniu operacji modulus, uzyskano niepodpisany odpowiednik liczby ujemnej, liczby, która została opakowana i była w związku z tym "duża". tutaj jest przykładowy program wykazać:niepodpisany przelew z operatorem modulus w 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; 

} 

ten produkuje następujące dane wyjściowe, na moim komputerze x86_64:

-1 
4294967295 
18446744073709551104 
-512 
1536 
2047 

1536 jest liczbą spodziewałem, ale (uint32_t) (- 512) jest numer, który otrzymywałem, co, jak można sobie wyobrazić, trochę wyrzuciło.

tak, domyślam się, że moje pytanie brzmi następująco: dlaczego operacja modułowa między dwiema niepodpisanymi liczbami, w tym przypadku, daje liczbę większą niż dzielnik (to znaczy liczbę ujemną)? czy istnieje powód, dla którego to zachowanie jest preferowane?

+1

2600000000 to int (a może 64-bitowy int - długi lub długi long), który mógł spowodować, że wynik mnożenia stał się (podpisany) długim. Na jakiej jesteś platformie? – Random832

Odpowiedz

3

Myślę, że powodem jest to, że kompilator jest interpretowanie 2600000000 dosłowny jako podpisany liczby 64-bitowej, ponieważ nie pasuje do podpisanego 32-bitowego int. Jeśli zastąpisz numer numerem 2600000000U, powinieneś uzyskać oczekiwany rezultat.

+2

Właściwie OP odwołał się do UB, przekazując nieprawidłowe ciągi formatów do 'printf'. –

2

Nie mam odniesienia pod ręką, ale jestem całkiem pewny, kiedy robisz to mnożenie, to promuje je do int64_t, ponieważ musi zmusić dwie mnożniki do podpisanego typu integralnego. Spróbuj 2600000000u zamiast 2600000000 ....

Powiązane problemy