Дивні визначення макросів TRUE та FALSE


300

Наступні макроозначення я бачив у книзі кодування.

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

Там ніяких пояснень не було.

Будь ласка , поясніть мені , як це буде працювати , як TRUEі FALSE.


63
Я думаю, що це просто смішний спосіб визначити TRUE як 1, а FALSE як 0
BlackDwarf

160
Зауважте, що це жахлива ідея без дужок навколо цих виразів. Я маю на увазі, що з ними жахлива ідея , але без того, щоб ви просто просили довгу ніч налагодження.
TartanLlama

70
Чи можу я знати книгу кодування, на яку ви посилаєтесь?
artm

47
Я сподіваюся, що книга включила це як приклад поганого або навмисно незрозумілого коду.
Джон Ханна

31
@Daniel: Іншою ідеєю було б rand ()% 2 визначити MAYBE як rand ()% 2, так що це іноді == ІСТИНА, а іноді == ЛАЖНА.
Кайзерлуді

Відповіді:


380

Подивимось: '/' / '/'означає charбуквальне /, поділене самим charбуквальним '/'. Результат такий, що звучить розумно TRUE.

І '-' - '-'означає charбуквальне '-', відняте від себе. Це нуль ( FALSE).

З цим є дві проблеми: по-перше, це не читається. Використання 1і 0абсолютно краще. Крім того, як зазначили TartanLlama та KerrekSB, якщо ви коли-небудь будете використовувати це визначення, будь ласка, додайте навколо них круглі дужки, щоб у вас не було сюрпризів:

#include <stdio.h>

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

int main() {
        printf ("%d\n", 2 * FALSE);
        return 0;
}

Це надрукує значення charлітералу '-'(45 у моїй системі).

З дужками:

#define TRUE  ('/'/'/')
#define FALSE ('-'-'-')

програма правильно виводить нуль, навіть якщо не має особливого сенсу множувати значення істини на ціле число, але це лише приклад виду несподіваних помилок, які можуть вкусити вас, якщо ви не скористаєтеся дужками макросів.


6
Чорт забирав багато, щоб зрозуміти це: навіть думав, що це дивна річ, як гліфи ... не знаю xD
Луїс Масуеллі

8
Насправді є сенс помножити на значення істини. Для відступу в іспиті * should_indent призведе до 0 або відступу на основі того, чи слід_indent без розгалуження. (Я здогадуюсь, що це поганий приклад, коли робота з текстовим розгалуженням тексту не має значення (я бачив цю техніку в шейдерах і в XPATH (як занадто різні, і я не пам’ятаю точну форму))
Alpedar

2
Альпедар - але це не концептуально і математично не має сенсозного для цього - у цьому випадку було б зрозуміліше (і концептуально це має сенс) використовувати ifзамість множення TRUEна ціле число.
Jay

4
Чудове пояснення. Майте золотий знак!
Майкл Хемптон

2
Логічне заперечення може бути реалізовано як notx = TRUE- x;і працює чудово. Окрім того, що TRUE-FALSEце -44 (припускаючи ASCII)
Хаген фон Ейтцен

89

Це просто інший спосіб написання

#define TRUE 1
#define FALSE 0

Вираз '/'/'/'поділить саму значенню '/', яка дасть 1 як результат.

Вираз '-'-'-'буде субстратувати значення char '-'від себе, яке дасть 0 в результаті.

Дужки навколо цілих defineвиразів відсутні, однак це може призвести до помилок у коді за допомогою цих макросів. Відповідь Джея наголошує на цьому досить добре.

Прикладом сценарію "реального життя", коли забуття дужок може бути шкідливим, - комбіноване використання цих макросів із оператором передачі в стилі C. Якщо хтось вирішить, наприклад, передати ці вирази boolв 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;
}

Ось що ми отримуємо:

True: 0
False: -44

Так (bool) TRUEби насправді оцінити false, і (bool) FALSEоцінив би true.


4
Приклад хороший :)
Kit Fisto

44

Це рівнозначно письму

#define TRUE 1
#define FALSE 0

Те, що '/'/'/'насправді робить вираз , - це ділення персонажа /(незалежно від його числового значення) саме собою, так воно і стає 1.

Аналогічно, вираз '-'-'-'віднімає персонаж -від себе і оцінює до 0.

Краще було б написати

#define TRUE ('/'/'/')
#define FALSE ('-'-'-')

щоб уникнути випадкової зміни значень при використанні з іншими операторами більш високого пріоритету.


5
ЛОЛ! Ось чому макроси слід правильно скористатись дужками.
0605002

3 права на сферу, і ви опинитесь там же
Derek 朕 會 功夫

@KerrekSB Ні, але три ліви роблять :)
Тім Лонг

33

Джей уже відповів, чому значення цих виразів є 0і 1.

Заради історії, ці вирази '/'/'/'і '-'-'-'з одного з входжень першого Міжнародного заплутаних C Code Contest в 1984 році :

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);}

(Посилання на програму тут є натяком на те, що ця програма робить на сторінці IOCCC вище.)

Крім того, якщо я добре пам’ятаю ці вирази як затуманені макроси TRUEта FALSEбули також висвітлені у книзі «Замучені С та інші містерії» Дон Лібс (1993).


7

Це веселий спосіб для написання макросів для Trueта False.

Оскільки було надано багато пояснень, /означає 1 байт (відповідно до ASCII), коли розділиться сам по собі, він дасть вам, 1що буде трактуватися як Trueі аналогічно, -це знову число байтів, якщо відняти те саме значення, яке воно вам дасть, 0яке буде інтерпретовано якfalse

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

отже, ми можемо замінити /або -будь-який, який нам подобається, наприклад:

#define TRUE  '!'/'!'
#define FALSE 'o'-'o'

Збереже те саме значення, що й вихідний вираз.


6

Почнемо з істинного. Ви можете його читати як '/' / '/', що означає "символ" / "розділений на символ" / "". Оскільки кожен символ у C є числовим значенням (на один байт), його можна читати як "значення символу ASCII" / ", поділене на значення ASCII того самого символу", що означає 1 (тому що, очевидно, x / x дорівнює 1). Отже, TRUEє 1.

Бо FALSEце ж міркування: '-'-'-'читає '-' - '-', тобто "значення ASCII '-' мінус значення ASCII '-'", що дорівнює 0. Отже, FALSEдорівнює 0.

Це неприємний спосіб констатувати очевидне.


7
Це не має нічого спільного з ASCII.
Керрек СБ

6
@Fabien: Це не залежить від ASCII. '/'/'/'дорівнює 1 для будь-якого дійсного набору символів, як '/' == 47(як це є в ASCII), або '/' == 97(як це є в EBCDIC), або будь-якого іншого значення.
Кіт Томпсон

4
@Pawel: Реалізація в відповідно C не може відобразити '/'в 0. Це значення зарезервовано для нульового символу.
Кіт Томпсон

2
Ти ведеш педантичність.
Матей208

3
@ Matheus208 Якщо Павель був педантичним, то це ('-'-'-'), оскільки його точка базувалася на нестандартній умові; описуючи зауваження Кіта як педантичні, можливо, буде більше ('/' / '/'), але я б назвав їх "уточнюючими" (а з доданими смайлами "педантичний" мені, безумовно, здається "/" - "/"). Можливо ('-' / '-'), що коментарі, взяті разом, можна назвати педантичними, але, 1) чи не є це дещо обов'язковим у цій галузі? 2) вони змусили мене думати; і 3) Я дещо зрозуміліший у деяких речах, ніж я був. І так, я гадаю, я сам педантичний! (Але мені зрозуміліше, що означає "педантичний", ніж я був ;;-)
Жора
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.