Dlaczego typ boolowski w C ++ obsługuje ++, ale nie -?

29

Dlaczego operator --nie istnieje dla bool, a dla operatora ++?

Próbowałem w C ++ i nie wiem, czy moje pytanie dotyczy innego języka. Będę również szczęśliwy.

Wiem , że mogę używać operatora ++z boolem. To sprawia, że ​​każdy bool jest równy prawdzie.

bool b = false;
b++;
// Now b == true.

Dlaczego nie możemy używać operatora --w odwrotny sposób?

bool b = true;
b--;
// Now b == false;

Nie jest to zbyt przydatne, ale jestem ciekawy.

aloisdg mówi Przywróć Monikę
źródło
8
To pytanie na StackOverflow może być pouczające.
Blrfl
Więc powód historii. Dziękuję za link. Czy potrafisz napisać odpowiedź, a ja uważam ją za rozwiązaną?
aloisdg mówi Przywróć Monikę
Same linki nie dają dobrych odpowiedzi, i nie ma dobrego mechanizmu oznaczania tni pytania duplikatem czegoś na innej stronie SE.
Blrfl
1
Powinniśmy więc otworzyć temat w meta.stackexchange.com lub coś takiego. Myślę, że powinieneś dostać trochę karmy za dobre łącze, a jeśli ktoś cię poprze, autor oryginalnej odpowiedzi powinien zdobyć trochę karmy. W rzeczywistości pierwotne pytanie również powinno uzyskać trochę karmy.
aloisdg mówi Przywróć Monikę
2
Duplikaty @aloisdg cross site są starym problemem w MSO. Śledź połączone pytania, aby uzyskać pełniejszy obraz.

Odpowiedzi:

53

W dawnych czasach C nie było typu logicznego. Ludzie używali intdo przechowywania danych logicznych i działało to głównie. Zero było fałszywe, a wszystko inne było prawdą.

Oznaczało to, że gdybyś wziął, int flag = 0;a później zrobił, flag++wartość będzie prawdziwa. Działa to bez względu na wartość flagi (chyba że dużo to zrobiłeś, przewrócił się i wróciłeś do zera, ale zignoruj ​​to) - zwiększenie flagi, gdy jej wartość wynosiła 1, dałoby 2, co wciąż było wartością prawdziwe.

Niektóre osoby wykorzystały to do bezwarunkowego ustawienia wartości boolowskiej na true. Nie jestem pewien, czy kiedykolwiek stał się idiomatyczny , ale jest w jakimś kodzie.

To nigdy nie zadziałało --, ponieważ gdyby wartość była inna niż 1 (która mogłaby być), wartość nadal nie byłaby fałszywa. A jeśli to było już false ( 0) i wykonałeś na nim operator dekrementacji, nie pozostanie on fałszywy.

Podczas przenoszenia kodu z C do C ++ na początku bardzo ważne było, aby kod C zawarty w C ++ był nadal w stanie działać. I tak w specyfikacji dla C ++ (sekcja 5.2.6 (na stronie 71)) czytamy:

Wartość uzyskana przez zastosowanie Postfiksa ++ jest wartością, którą operand miał przed zastosowaniem operatora. [Uwaga: uzyskana wartość jest kopią pierwotnej wartości] Operand będzie wartością modyfikowalną. Typ argumentu powinien być typem arytmetycznym lub wskaźnikiem do pełnego typu obiektu. Po zanotowaniu wyniku wartość obiektu jest modyfikowana przez dodanie do niego 1, chyba że obiekt jest typu bool, w którym to przypadku jest ustawiony na true. [Uwaga: to zastosowanie jest przestarzałe, patrz załącznik D.]

Argument postfix - jest dekrementowany analogicznie do operatora postfix ++, z tym wyjątkiem, że operand nie jest typu bool.

Jest to ponownie wspomniane w sekcji 5.3.2 (dla operatora prefiksu - 5.2.6 był na postfiksie)

Jak widać, jest to przestarzałe (załącznik D w dokumencie, strona 709) i nie należy go używać.

Ale właśnie dlatego. Czasami możesz zobaczyć kod. Ale nie rób tego.

Społeczność
źródło
5
„Niektórzy używali tego do bezwarunkowego ustawiania wartości logicznej na wartość true”. Nazwijmy ich cholernymi głupcami, a nie ludźmi.
Deduplicator,
@Deduplicator: Być może była to kwestia wydajności: załadowanie wartości do zmiennej mogło zająć więcej cykli procesora niż zwiększenie zmiennej. Oczywiście to prawdopodobnie nie ma znaczenia na nowoczesnych komputerach.
Giorgio,
1
@Giorgio, które jest całkiem prawdopodobne. Pamiętaj, że C napisano tak, aby ściśle pasowało do zestawu instrukcji PDP-7, a PDP-11 miał inne poprawki. Z tego - „Ludzie często zgadują, że zostali stworzeni do korzystania z trybów automatycznego zwiększania i automatycznego zmniejszania adresów zapewnianych przez DEC PDP-11, w których C i Unix po raz pierwszy stały się popularne. Jest to historycznie niemożliwe, ponieważ nie było PDP- 11, gdy opracowano B. PDP-7 miał jednak kilka komórek pamięci z „automatyczną inkrementacją”, z tą właściwością, że pośrednie odwołanie do nich poprzez pamięć zwiększyło komórkę ”.
@Deduplicator: W kodzie, który używa liczb całkowitych dla wartości logicznych, zmienna, która jest zwiększana dla każdego ... cokolwiek ... może działać zarówno jako licznik (ile razy był zwiększany), jak i jako wartość logiczna (czy w ogóle została zwiększona lub nie).
Keith Thompson,
2

Aby częściowo poradzić sobie ze starszym kodem, który używał intlub podobny jako typ logiczny.

Mike Graham
źródło
1
Moje pytanie jest duplikatem stąd stackoverflow.com/questions/3450420/… . Nawiasem mówiąc, dziękuję za odpowiedź.
aloisdg mówi Przywróć Monikę
1

Aby zrozumieć historyczne znaczenie tego pytania, należy rozważyć przypadek Therac-25. Therac-25 był urządzeniem medycznym, które zapewniało promieniowanie pacjentom chorym na raka. Nękane były złymi praktykami programowania, które przyczyniły się do złych wyników w zakresie bezpieczeństwa (przypisano mu wiele zgonów).

http://courses.cs.vt.edu/professionalism/Therac_25/Therac_1.html

(przejdź na dół strony 3)

Każde przejście przez procedurę testu konfiguracji zwiększa kontrolę pozycji górnego kolimatora, zmienną wspólną o nazwie Class3. Jeśli klasa 3 jest niezerowa, występuje niespójność i leczenie nie powinno być kontynuowane. Wartość zerowa dla klasy 3 wskazuje, że odpowiednie parametry są zgodne z obróbką, a wiązka nie jest hamowana.

...

Podczas konfiguracji maszyny test konfiguracji zostanie wykonany kilkaset razy, ponieważ sam się przestawia w oczekiwaniu na inne zdarzenia. W kodzie zmienna klasy 3 jest zwiększana o jeden w każdym przejściu przez test konfiguracji. Ponieważ zmienna Class3 ma 1 bajt, może zawierać maksymalnie 255 cyfr dziesiętnych. Zatem przy każdym 256. przejściu kodu testu konfiguracji zmienna przepełnia się i ma wartość zerową. Oznacza to, że przy każdym 256-tym przejściu testu konfiguracji górny kolimator nie zostanie sprawdzony, a błąd górnego kolimatora nie zostanie wykryty. Prześwietlenie wystąpiło, gdy operator nacisnął przycisk „set” dokładnie w momencie, gdy klasa 3 przewróciła się do zera. W ten sposób Chkcol nie został wykonany, a F $ mal nie został ustawiony, aby wskazać, że górny kolimator nadal znajduje się w pozycji światła polowego. Oprogramowanie włączyło pełne 25 MeV bez celu i bez skanowania. Powstała wysoce skoncentrowana wiązka elektronów, która została rozproszona i odchylona przez lustro ze stali nierdzewnej, które było na drodze.

Therac-25 użył czegoś w rodzaju odpowiednika operator++na bool. Jednak używanym językiem programowania nie był C ++, a ich typ danych nie bool. Jednak w przeciwieństwie do gwarancji w C ++ zwykła liczba całkowita po prostu rośnie. Ich typ danych był równoważny uint8_t.

C ++ postanowił zachować operator++ostrożność dla osób przyzwyczajonych do programowania w ten sposób, ale zamiast zwiększać wartość, po prostu ustawia ją, trueaby zapobiec takim rzeczom.

Uwaga: operator++(bool)jest przestarzała.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf

Załącznik D do C ++ 14:

D.1 Operator inkrementacji z operandem bool
Użycie operandu typu bool z operatorem ++ jest przestarzałe (patrz 5.3.2 i 5.2.6).

David Stone
źródło
To wyjaśniałoby, dlaczego jest przestarzałe, ale nie wyjaśnia, dlaczego istnieje.
Istnieje, ponieważ niektórzy ludzie ustawiali wartość boolowską, zwiększając ją podczas programowania w C. C ++ został zaprojektowany w celu ułatwienia przejścia z C, więc wsparli go booltypem. Chciałem tylko podać historyczny przykład tego, kiedy ludzie tak zaprogramowali.
David Stone