Myślę, że jest to po prostu zabawny sposób zdefiniowania PRAWDA jako 1, a FAŁSZ jako 0
BlackDwarf
160
Zauważ, że to okropny pomysł bez nawiasów wokół tych wyrażeń. Mam na myśli to okropny pomysł z nimi, ale bez pytania o długą noc debugowania.
TartanLlama,
70
Czy mogę poznać książkę, do której się odwołujesz?
artm
47
Mam nadzieję, że książka zawiera to jako przykład złego lub celowo niejasnego kodu.
Jon Hanna,
31
@Daniel: Innym pomysłem byłoby rand ()% 2 zdefiniowanie MAYBE jako rand ()% 2, więc czasami jest to == PRAWDA, a czasami == FAŁSZ.
Kaiserludi,
Odpowiedzi:
380
Zobaczmy: '/' / '/'oznacza charliterał /podzielony przez sam charliterał '/'. Wynik jest taki, co wydaje się rozsądne TRUE.
I '-' - '-'oznacza chardosłowne '-', odjęte od siebie. To zero ( FALSE).
Są z tym dwa problemy: po pierwsze, nie można go odczytać. Korzystanie 1i 0jest absolutnie lepsze. Ponadto, jak zauważyli TartanLlama i KerrekSB, jeśli kiedykolwiek będziesz używać tej definicji, dodaj nawiasy wokół nich, abyś nie miał żadnych niespodzianek:
Spowoduje to wydrukowanie wartości charliterału '-'(45 w moim systemie).
Z nawiasami:
#define TRUE ('/'/'/')#define FALSE ('-'-'-')
program poprawnie drukuje zero, mimo że nie ma większego sensu mnożenie wartości prawdy przez liczbę całkowitą, ale jest to tylko przykład nieoczekiwanych błędów, które mogą cię ugryźć, jeśli nie nawiasujesz makr w nawiasie.
Cholera, dużo czasu zajęło mi zrozumienie: nawet myślałem, że to dziwna rzecz jako glify ... nie wiem xD
Luis Masuelli
8
Właściwie sensowne jest mnożenie z wartością prawdy. Na przykład wcięcie * should_indent spowoduje albo 0, albo wcięcie na podstawie tego, czy should_indent bez rozgałęzienia. (Wydaje mi się, że jest to zły przykład, gdy praca z tekstem rozgałęzianie pojedyncze nie ma znaczenia, (Widziałem tę technikę w shaderach i XPATH (zarówno zbyt różne, jak i nie pamiętam dokładnej formy))
Alpedar
2
Alpedar - ale nie ma sensu czynić tego pojęciowo i matematycznie - w tym przypadku bardziej zrozumiałe (i koncepcyjnie sensowne) jest użycie ifzamiast mnożenia TRUEprzez liczbę całkowitą.
Jay
4
Świetne wyjaśnienie. Zdobądź złotą odznakę!
Michael Hampton
2
Logiczna negacja może być zaimplementowana jako notx = TRUE- x;i działa dobrze. Tyle że TRUE-FALSE-44 (przy założeniu ASCII)
Hagen von Eitzen
89
To tylko inny sposób pisania
#define TRUE 1#define FALSE 0
Wyrażenie '/'/'/'samo podzieli wartość char '/', co w rezultacie da 1.
Wyrażenie '-'-'-'odejmie '-'od siebie wartość char , co w rezultacie da 0.
defineBrakuje jednak nawiasów wokół całych wyrażeń, co może prowadzić do błędów w kodzie przy użyciu tych makr. Odpowiedź Jaya całkiem dobrze na to odpowiada.
Przykładem „rzeczywistego” scenariusza, w którym zapomnienie nawiasów klamrowych może być szkodliwe, jest łączenie użycia tych makr z operatorem rzutowania w stylu C. Jeśli na przykład ktoś zdecyduje się rzutować na te wyrażenia boolw C ++:
int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\
o, world!\n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);}
(Link do programu tutaj , podpowiedź tego, co ten program robi na stronie IOCCC powyżej).
Również jeśli dobrze pamiętam te wyrażenia jako zaciemnione makra dla TRUEi FALSEzostały one również omówione w książce Don Obcuscated C and Other Mysteries autorstwa Don Libesa (1993).
Ponieważ podano wiele wyjaśnień, /oznacza to, że 1-bajtowa liczba (zgodnie z ASCII) po podzieleniu przez siebie daje ci to, 1co będzie traktowane, Truei podobnie -jest znowu liczbą bajtów po odjęciu tej samej wartości, 0którą ci da, która zostanie zinterpretowana jakofalse
#define TRUE '/'/'/'#define FALSE '-'-'-'
dlatego możemy zastąpić /lub -dowolnym char, który nam się podoba, na przykład:
#define TRUE '!'/'!'#define FALSE 'o'-'o'
Zachowuje to samo znaczenie, co oryginalne wyrażenie.
Zacznijmy od prawdy. Możesz go odczytać jako '/' / '/', co oznacza „znak” / „podzielony przez znak” / „”. Ponieważ każdy znak w C jest wartością liczbową (w jednym bajcie), można go odczytać jako „wartość ASCII znaku” / ”podzieloną przez wartość ASCII tego samego znaku”, co oznacza 1 (ponieważ, oczywiście, x / x to 1). Stąd TRUEjest 1.
Ponieważ FALSEma to samo rozumowanie: '-'-'-'czyta '-' - '-', tj. „Wartość ASCII z„ - ”minus wartość ASCII z„ - ”„, która wynosi 0. Stąd FALSEwynosi 0.
@Fabien: To nie zależy od ASCII. '/'/'/'wynosi 1 dla dowolnego prawidłowego zestawu znaków, czy to '/' == 47(jak w ASCII), '/' == 97(jak w EBCDIC), czy jakakolwiek inna wartość.
Keith Thompson,
4
@Pawel: Implementacja zgodna C nie można mapować '/'do 0. Ta wartość jest zarezerwowana dla znaku zerowego.
Keith Thompson,
2
Jesteś pedantyczny.
Matheus208,
3
@ Matheus208 Jeśli Paweł był pedantyczny, to („-'-”-”), ponieważ jego punkt widzenia był oparty na nieokreślonym stanie; opisywanie uwag Keitha jako pedantycznych może być więcej („/” / „/”), ale nazwałbym je „wyjaśniającymi” (a wraz z dodanymi buźkami „pedantyczny” zdecydowanie wydaje mi się „/” - ”/”). Może być („-” / „-”), że zebrane komentarze można nazwać pedantycznymi, ale: 1) czy nie jest to nieco obowiązkowe w tej dziedzinie? 2) zmusili mnie do myślenia; i 3) Jestem trochę jaśniejszy w niektórych sprawach niż byłem. I tak, chyba sam jestem pedantyczny! (Ale jaśniej rozumiem, co znaczy „pedantyczny” niż byłem! ;-)
Odpowiedzi:
Zobaczmy:
'/' / '/'
oznaczachar
literał/
podzielony przez samchar
literał'/'
. Wynik jest taki, co wydaje się rozsądneTRUE
.I
'-' - '-'
oznaczachar
dosłowne'-'
, odjęte od siebie. To zero (FALSE
).Są z tym dwa problemy: po pierwsze, nie można go odczytać. Korzystanie
1
i0
jest absolutnie lepsze. Ponadto, jak zauważyli TartanLlama i KerrekSB, jeśli kiedykolwiek będziesz używać tej definicji, dodaj nawiasy wokół nich, abyś nie miał żadnych niespodzianek:Spowoduje to wydrukowanie wartości
char
literału'-'
(45 w moim systemie).Z nawiasami:
program poprawnie drukuje zero, mimo że nie ma większego sensu mnożenie wartości prawdy przez liczbę całkowitą, ale jest to tylko przykład nieoczekiwanych błędów, które mogą cię ugryźć, jeśli nie nawiasujesz makr w nawiasie.
źródło
if
zamiast mnożeniaTRUE
przez liczbę całkowitą.notx = TRUE- x;
i działa dobrze. Tyle żeTRUE-FALSE
-44 (przy założeniu ASCII)To tylko inny sposób pisania
Wyrażenie
'/'/'/'
samo podzieli wartość char'/'
, co w rezultacie da 1.Wyrażenie
'-'-'-'
odejmie'-'
od siebie wartość char , co w rezultacie da 0.define
Brakuje jednak nawiasów wokół całych wyrażeń, co może prowadzić do błędów w kodzie przy użyciu tych makr. Odpowiedź Jaya całkiem dobrze na to odpowiada.Przykładem „rzeczywistego” scenariusza, w którym zapomnienie nawiasów klamrowych może być szkodliwe, jest łączenie użycia tych makr z operatorem rzutowania w stylu C. Jeśli na przykład ktoś zdecyduje się rzutować na te wyrażenia
bool
w C ++:Oto, co otrzymujemy:
Więc
(bool) TRUE
faktycznie oceniałfalse
i(bool) FALSE
oceniałtrue
.źródło
Jest to równoważne z pisaniem
To, co
'/'/'/'
faktycznie robi wyrażenie , polega na podzieleniu znaku/
(bez względu na jego wartość liczbową), więc staje się1
.Podobnie, wyrażenie
'-'-'-'
odejmuje znak-
od siebie i ocenia na0
.Lepiej byłoby pisać
aby uniknąć przypadkowej zmiany wartości w przypadku użycia z innymi operatorami o wyższym priorytecie.
źródło
Jay już odpowiedział, dlaczego wartości tych wyrażeń to
0
i1
.Ze względów historycznych te wyrażenia
'/'/'/'
i'-'-'-'
pochodzą z jednego z wpisów z 1st International Code zamaskowany C konkursu w 1984 roku :(Link do programu tutaj , podpowiedź tego, co ten program robi na stronie IOCCC powyżej).
Również jeśli dobrze pamiętam te wyrażenia jako zaciemnione makra dla
TRUE
iFALSE
zostały one również omówione w książce Don Obcuscated C and Other Mysteries autorstwa Don Libesa (1993).źródło
To zabawny sposób pisania makr dla
True
iFalse
.Ponieważ podano wiele wyjaśnień,
/
oznacza to, że 1-bajtowa liczba (zgodnie z ASCII) po podzieleniu przez siebie daje ci to,1
co będzie traktowane,True
i podobnie-
jest znowu liczbą bajtów po odjęciu tej samej wartości,0
którą ci da, która zostanie zinterpretowana jakofalse
dlatego możemy zastąpić
/
lub-
dowolnym char, który nam się podoba, na przykład:Zachowuje to samo znaczenie, co oryginalne wyrażenie.
źródło
Zacznijmy od prawdy. Możesz go odczytać jako
'/' / '/'
, co oznacza „znak” / „podzielony przez znak” / „”. Ponieważ każdy znak w C jest wartością liczbową (w jednym bajcie), można go odczytać jako „wartość ASCII znaku” / ”podzieloną przez wartość ASCII tego samego znaku”, co oznacza 1 (ponieważ, oczywiście, x / x to 1). StądTRUE
jest 1.Ponieważ
FALSE
ma to samo rozumowanie:'-'-'-'
czyta'-' - '-'
, tj. „Wartość ASCII z„ - ”minus wartość ASCII z„ - ”„, która wynosi 0. StądFALSE
wynosi 0.To paskudny sposób na stwierdzenie oczywistości.
źródło
'/'/'/'
wynosi 1 dla dowolnego prawidłowego zestawu znaków, czy to'/' == 47
(jak w ASCII),'/' == 97
(jak w EBCDIC), czy jakakolwiek inna wartość.'/'
do0
. Ta wartość jest zarezerwowana dla znaku zerowego.