W książce kodowej widziałem następujące definicje makr.
#define TRUE '/'/'/'
#define FALSE '-'-'-'
Nie było tam żadnego wyjaśnienia.
Proszę wyjaśnić mi, jak będą one działać jako TRUEi FALSE.
W książce kodowej widziałem następujące definicje makr.
#define TRUE '/'/'/'
#define FALSE '-'-'-'
Nie było tam żadnego wyjaśnienia.
Proszę wyjaśnić mi, jak będą one działać jako TRUEi FALSE.
Odpowiedzi:
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:
#include <stdio.h>
#define TRUE '/'/'/'
#define FALSE '-'-'-'
int main() {
printf ("%d\n", 2 * FALSE);
return 0;
}
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.
ifzamiast mnożenia TRUEprzez liczbę całkowitą.
notx = TRUE- x;i działa dobrze. Tyle że TRUE-FALSE-44 (przy założeniu ASCII)
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 ++:
#include <iostream>
#define TRUE '/'/'/'
#define FALSE '-'-'-'
int main() {
std::cout << "True: " << (bool) TRUE << std::endl;
std::cout << "False: " << (bool) FALSE << std::endl;
return 0;
}
Oto, co otrzymujemy:
True: 0
False: -44
Więc (bool) TRUEfaktycznie oceniał falsei (bool) FALSEoceniał true.
Jest to równoważne z pisaniem
#define TRUE 1
#define FALSE 0
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 na 0.
Lepiej byłoby pisać
#define TRUE ('/'/'/')
#define FALSE ('-'-'-')
aby uniknąć przypadkowej zmiany wartości w przypadku użycia z innymi operatorami o wyższym priorytecie.
Jay już odpowiedział, dlaczego wartości tych wyrażeń to 0i 1.
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 :
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).
To zabawny sposób pisania makr dla Truei False.
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.
To paskudny sposób na stwierdzenie oczywistości.
'/'/'/'wynosi 1 dla dowolnego prawidłowego zestawu znaków, czy to '/' == 47(jak w ASCII), '/' == 97(jak w EBCDIC), czy jakakolwiek inna wartość.
'/'do 0. Ta wartość jest zarezerwowana dla znaku zerowego.