Странные определения макросов TRUE и FALSE

300

Я видел следующие макроопределения в книге кодирования.

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

Там не было объяснений.

Пожалуйста, объясните мне, как они будут работать как TRUE и FALSE.

  • 62
    Я думаю, что это просто забавный способ определить TRUE как 1 и FALSE как 0
  • 157
    Обратите внимание, что это ужасная идея без скобок вокруг этих выражений. Я имею в виду, что это ужасная идея с ними, но без этого вы просто просите долгой ночи отладки.
Показать ещё 32 комментария
Теги:
obfuscation
boolean
macros

6 ответов

385
Лучший ответ

Посмотрим: '/' / '/' означает 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 literal '-' (45 в моей системе).

С круглыми скобками:

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

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

  • 5
    Черт, мне потребовалось много времени, чтобы понять это: я даже подумал, что это странная вещь, как глифы ... не знаю xD
  • 8
    На самом деле имеет смысл умножить значение истины. Например, для отступа * should_indent будет либо 0, либо отступ, в зависимости от того, следует ли делать must_indent без ветвления. (Полагаю, что это плохой пример, когда работа с одним текстовым переходом не имеет значения, (я видел эту технику в шейдерах и в XPATH (оба слишком разные, и я не помню точную форму))
Показать ещё 5 комментариев
80

Это просто еще один способ написания

#define TRUE 1
#define FALSE 0

Выражение '/'/'/' само по себе разделит значение char '/', что даст результат 1.

Выражение '-'-'-' будет вычитать значение char '-' от самого себя, что даст в результате 0.

Скобки вокруг всего выражения define отсутствуют, хотя это может привести к ошибкам в коде с использованием этих макросов. Jay отвечает, это довольно хорошо.

Примером сценария "реальной жизни", в котором забывание скобок может быть вредным, является совместное использование этих макросов с оператором литья в стиле C. Если кто-то решит включить эти выражения в bool в С++, например:

#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
    Пример хороший :)
42

Это эквивалентно записи

#define TRUE 1
#define FALSE 0

То, что на самом деле выполняет выражение '/'/'/', делит символ / (независимо от его числового значения), поэтому он становится 1.

Аналогично, выражение '-'-'-' вычитает символ - из себя и оценивается как 0.

Лучше написать

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

чтобы избежать случайного изменения значений при использовании с другими операторами с более высоким приоритетом.

  • 34
    Что 2 * FALSE - два ошибки делают правильно?
  • 5
    ЛОЛ! Вот почему макросы должны быть в скобках.
Показать ещё 3 комментария
29

Джей уже ответил, почему значения этих выражений 0 и 1.

Для истории эти выражения '/'/'/' и '-'-'-' взяты из одной из записей 1-й Международный конкурс Obfuscated C Code в 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, также были рассмотрены в "Obfuscated C and Other Mysteries" книга Дона Либеса (1993).

6

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

Как было сделано много объяснений, / означает 1-байтовое число (согласно ASCII), когда он делит сам по себе, он дает вам 1, который будет обрабатываться как True, а также - снова является байтовым числом при вычитании того же значения он дает вам 0, который будет интерпретироваться как False

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

следовательно, мы можем заменить / или - на любой char, который нам нравится, например:

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

Будет иметь то же значение, что и исходное выражение.

6

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

Для FALSE, его те же рассуждения: '-'-'-' читает '-' - '-', то есть "значение ASCII '-' за вычетом значения ASCII '-'", которое равно 0. Следовательно, FALSE 0.

Это неприятный способ сформулировать очевидное.

  • 7
    Это не имеет ничего общего с ASCII.
  • 1
    @KerrekSB, на практике, да, это так, если только вы не разрабатываете очень специфическую архитектуру, которая, вероятно, не имеет отношения к вопросу OP.
Показать ещё 9 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню