2013-03-30 11 views
8

Dlaczego wielu Online Judges doradza "nie używaj specyfikatora% lld do odczytu lub zapisu 64-bitowych liczb całkowitych w С ++. Preferowane jest użycie cin, strumieni cout lub% I64d specifier." ?Dlaczego użycie cin, cout lub% I64d jest preferowane w porównaniu z% lld specyfikatorem w C++?

+6

Ponieważ nie możesz być pewien, że 'long long' ma na przykład długość 64 bitów? –

+1

Ponieważ użycie 'printf' nie jest bezpieczne. Jeśli użytkownik przekazuje inny typ, to daje niezdefiniowane zachowanie.Podczas gdy z 'cout' kompilator odpowiednio wybiera poprawną wersję przeciążenia w zależności od typu lub zwraca błąd, nie ma niezdefiniowanego zachowania. –

+0

(Ponieważ używanie C++ nie jest bezpieczne dla mózgu ...) –

Odpowiedz

8

Uważam, że odpowiedź jest związana %lld oznacza long long decimal, który nie jest gwarancją 64-bitowych. Może to być na przykład 128-bitowy w niektórych systemach. (Chociaż, jeśli zmienna jest long long raczej niż, powiedzmy, uint64_t, potem oczekiwać %lld jest dobrą rzeczą, aby użyć - czy to nie udać na odwrót)

Niestety, projekt printf i scanf i ich rodzeństwo jest taki, że implementacja kompilatora i format muszą być zgodne.

Oczywiście cout i cin są bezpieczne w tym sensie, że kompilator wybierze odpowiednią moc i tłumaczenie wejściowego w sobie.

Może też mieć coś wspólnego z tym, co kompilator (s) „online judge” używania - myślę kompilatory Microsoft w pewnym momencie obsługiwane 64-bitowe liczby całkowite, ale nie long long, a zatem nie mają %lld, ale miał %l64d.

+0

Natknąłem się na ten link http://codeforces.com/blog/entry/417# który mówi: Jeśli przesyłasz w "GNU C++" lub "GNU C", użyj tego: printf ("% I64d \ n" , n); , ale NIE to: printf ("% lld \ n", n); Jeśli prześlesz w "MS C++", oba warianty powinny działać. – rishabh

+0

Podejrzewam, że to dlatego, że GNU C faktycznie używa starszej biblioteki środowiska wykonawczego MS VC (ponieważ glibc nie jest łatwo dostępny dla systemu Windows). –

4

W << i >> operatorzy na cin i cout posiada wersje dla każdej liczby całkowitej i rodzaju zmiennoprzecinkowej. Jeśli używasz cin i cout, wystarczy wykonać cin >> integer_variable lub cout << integer_variable i gotowe, cin i cout wymyśli, co zrobić.

Jeśli używasz jakiegoś rodzaju printf(), musisz być bardzo ostrożny w tym, co do niego przenosisz. Jeśli przechodzi on int, należy również przekazać jego specyfikacja typu "%d", dla unsigned int to "%u" dla long to "%ld", dla unsigned long long to "%llu" dla size_t to "%zu" i tak dalej. Jeśli przekażesz specyfikator typu, który nie jest zgodny z typem twojej liczby całkowitej, wywołasz niezdefiniowane zachowanie. W rezultacie Twój program może drukować nieprawidłowe numery lub uszkodzić się lub zawiesić lub zawiesić lub źle się zachowywać w jakiś inny tajemniczy sposób.

Teraz średnia język C++ 11 (i C99) posiada co najmniej jeden rodzaj całkowitą, która jest 64-bitowy lub dłużej, long long (unsigned i jego odpowiednika unsigned long long). Jeśli go używasz, musisz mieć świadomość, że może on być dłuższy niż 64 bity. Jeśli Twój kompilator dostarcza inny typ, __int64 lub int64_t (plus niepodpisana wersja tego samego), to dokładnie 64-bitowe, nie powinieneś mieszać i dopasowywać swoich specyfikatorów typów, ponieważ jest to często błędne wykonanie. Powinieneś nadal używać "%lld" i "%llu" dla long long i unsigned long long i cokolwiek jest odpowiednie dla (być może, "%I64d") i dla int64_t (PRId64 makro).

Zasadniczo należy unikać korzystania z funkcji printf()-like lub zachować ostrożność.

Powiązane problemy