2016-02-03 11 views
5

Znajduję to, co uważam za bardzo dziwne zachowanie. Rustc panikuje, gdy zmienna przepełnia się podczas pracy; To ma dla mnie sens. Podnosi jednak tylko ostrzeżenie, gdy przepełniona wartość jest przypisywana w czasie kompilacji. Czy nie powinien to być błąd czasu kompilacji? W przeciwnym razie dwa zachowania wydają się niekonsekwentne.Rustc ostrzega tylko, gdy wartość, która przepełnia, jest przypisana

Spodziewam się błąd czasu kompilacji:

fn main() { 
    let b: i32 = 3_000_000_000; 
    println!("{}", b); 
} 

produkuje:

<anon>:2:18: 2:31 warning: literal out of range for i32, #[warn(overflowing_literals)] on by default 
<anon>:2  let b: i32 = 3_000_000_000; 

Playground 1

to sens do mnie:

fn main() { 
    let b: i32 = 30_000; 
    let c: i32 = 100_000; 
    let d = b * c; 
    println!("{}", d); 
} 

produkuje:

thread '<main>' panicked at 'arithmetic operation overflowed', <anon>:4 
playpen: application terminated with error code 101 

Playground 2

Edit:

Biorąc pod uwagę komentarz przez FrancisGagné i mnie odkrycie, że Rust wdraża operatorów, które sprawdzają na przepełnienie podczas operacji, na przykład checked_mul, widzę, że trzeba samodzielnie przeprowadzać kontrole przelewów. To ma sens, ponieważ wersja oprogramowania powinna być zoptymalizowana, a ciągłe sprawdzanie, czy przepełnienia nie są zbyt kosztowne. Nie widzę już "niespójności". Nadal jestem jednak zaskoczony, że przypisanie wartości, która spowodowałaby przepełnienie, nie doprowadzi do kompilacji błędu czasu. W golang miałoby to: Go Playground

+0

Trudno jest zrobić dowolną stałą propagację. Ciągły ewaluator Rusta nie jest jeszcze wystarczająco mocny, ale jest bardzo prawdopodobne, że twój drugi przypadek zostanie ostrzeżony w pewnym momencie. Jeśli użyjesz stałych zamiast dozwolonych wiązań, otrzymasz ostrzeżenie nawet podczas mnożenia: http://is.gd/1k9xtX –

+0

oh. Źle zrozumiałem. Domyślam się, że wszyscy próbują stworzyć kompilację bez ostrzeżenia. –

+1

Należy zauważyć, że drugi program tylko panikuje w kompilacji debugowania; nie ma sprawdzeń przepełnienia w kompilacji wydania. Kompilacja wydania drugiego programu wypisuje '-1294967296', podobnie jak pierwszy program. –

Odpowiedz

3

Faktycznie, komentarze nie są zgodne z zachowania można zaobserwować:

  • w pierwszym przykładzie: dostajesz ostrzeżenie kompilacji, które ignorujesz, a więc kompilator wnioskuje, że chcesz owijania zachowanie
  • w drugim przykładzie: masz błąd run-time

przykład Go jest podobny do pierwszego przykładu Rust (oprócz tego, że Go, przez projekt, nie ma ostrzeżenia) .


rdza, niedomiar lub przelewowe skutkuje określono wartości które mogą być ! lub dolny w informatyce szczególną wartością, co oznacza, że ​​przepływ sterowania odchylania, które ogólnie oznacza albo aborcji lub wyjątku .

Specyfikacja ta pozwala na:

  • instrumentacji tryb debugowania złapać wszystkie przepełnienia na samym miejscu, w którym występują
  • nie instrumentacji trybu wyzwalania (z użyciem nie zawijania arytmetyczne)

, a mimo to oba tryby są zgodne ze specyfikacją.

Nie instrumentacji domyślnie, można, jeśli zdecydujesz i stosunkowo niewielki koszt wykonania poza ciężkim kodem numerycznym aktywować kontroli przepełnienia w wersji z prostym flagi.


na kosztach kontroli overflow: obecna sytuacja Rust/LLVM jest pomocne do debugowania, ale nie naprawdę zostały zoptymalizowane. W związku z tym koszt kontroli nad przepełnieniem. Jeśli sytuacja się poprawi, rustc może zdecydować, pewnego dnia, aby aktywować kontrolę nad przepełnieniem, nawet w wersji Release.

W Midori (a OS eksperymentalnej Microsoft opracowany w języku podobnym do C#), kontrola przepełnienia był włączony nawet w wersji buduje:

In Midori, we compiled with overflow checking on by default. This is different from stock C#, where you must explicitly pass the /checked flag for this behavior. In our experience, the number of surprising overflows that were caught, and unintended, was well worth the inconvenience and cost. But it did mean that our compiler needed to get really good at understanding how to eliminate unnecessary ones.

Najwyraźniej, poprawiły swoje kompilator tak, że:

  • to powodowałoby zakresy zmiennych i statycznie eliminuje kontrole graniczne i kontrole przekroczenia, jeśli to możliwe,
  • to sumowałoby kontrole w największym możliwym stopniu (jeden czek na mu Mogą potencjalnie przepełnić operacje)

Ten ostatni należy wykonać tylko w wersji Release (tracisz precyzję), ale zmniejsza liczbę gałęzi.

Jaki jest koszt?

Potencjalnie różne reguły arytmetyczne, które popadły w drodze optymalizacji:

  • w zwykłej arytmetyce, 64 + x - 128 może zostać zoptymalizowany do x - 64; z czeków przelewowych aktywowane kompilator może nie być w stanie wykonać tę optymalizację
  • wektoryzacja może być utrudniony też, jeśli kompilator nie ma przepełnienia sprawdzanie wektor Zabudowy
  • ...

Mimo to, chyba że kod jest silnie numeryczny (na przykład symulacje naukowe lub grafika), a następnie może mieć na nie istotny wpływ.

+0

Dziękuję. Bardzo wnikliwy. – Akavall

Powiązane problemy