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 TRUE
i 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 TRUE
i FALSE
.
Odpowiedzi:
Zobaczmy: '/' / '/'
oznacza char
literał /
podzielony przez sam char
literał '/'
. Wynik jest taki, co wydaje się rozsądne TRUE
.
I '-' - '-'
oznacza char
dosłowne '-'
, odjęte od siebie. To zero ( FALSE
).
Są z tym dwa problemy: po pierwsze, nie można go odczytać. Korzystanie 1
i 0
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:
#include <stdio.h>
#define TRUE '/'/'/'
#define FALSE '-'-'-'
int main() {
printf ("%d\n", 2 * FALSE);
return 0;
}
Spowoduje to wydrukowanie wartości char
literał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.
if
zamiast mnożenia TRUE
przez 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.
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 ++:
#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) TRUE
faktycznie oceniał false
i (bool) FALSE
oceniał 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 0
i 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 TRUE
i FALSE
został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 True
i False
.
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
#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 TRUE
jest 1.
Ponieważ FALSE
ma to samo rozumowanie: '-'-'-'
czyta '-' - '-'
, tj. „Wartość ASCII z„ - ”minus wartość ASCII z„ - ”„, która wynosi 0. Stąd FALSE
wynosi 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.