Какое из худших в мире злоупотреблений макросами и препроцессорами вы когда-либо встречали?


176

Какое из худших реальных злоупотреблений макросами / препроцессором вы когда-либо встречали (пожалуйста, не придумывайте ответы IOCCC * хаха *)?

Пожалуйста, добавьте короткий фрагмент или историю, если это действительно интересно. Цель состоит в том, чтобы научить чему-то, вместо того, чтобы всегда говорить людям «никогда не используйте макросы».


ps: я использовал макросы раньше ... но обычно я в конечном итоге избавляюсь от них, когда у меня есть "реальное" решение (даже если реальное решение встроено, поэтому оно становится похожим на макрос).


Бонус: приведите пример, где макрос был действительно лучше, чем не-макро решение.

Смежный вопрос: когда полезны макросы C ++?


+1 за привлечение внимания к безудержному насилию со стороны Макроса.
i_am_jorf

37
#define истинной ложной // счастливой отладки :)
n0rd

Сообщество вики означает, что никто не получит (или не потеряет) репутацию от голосов "за" / "против" по этому вопросу или его ответам Многие люди считают подобные вопросы дешевыми и легкими способами завоевать репутацию, поэтому, если вы отметите их как вики сообщества, люди с меньшей вероятностью потеряют форму и закроют ее.
Грэм Перроу

2
«люди, скорее всего, изогнутся и закроются»: вы намекаете на то, что не хотите смешного / смешного контента при переполнении стека?
Тревор Бойд Смит

2
Вкратце, препроцессор является частью языка и, следовательно, не является злым / неправильным в использовании, как и все остальное.
Мистер Бой

Ответы:


410

По памяти это выглядело примерно так:

#define RETURN(result) return (result);}

int myfunction1(args) {
    int x = 0;
    // do something
    RETURN(x)

int myfunction2(args) {
    int y = 0;
    // do something
    RETURN(y)

int myfunction3(args) {
    int z = 0;
    // do something
    RETURN(z)

Да, верно, никаких закрывающих скобок в любой из функций. Подсветка синтаксиса была беспорядочной, поэтому он использовал vi для редактирования (не vim, у него есть подсветка синтаксиса!)

Он был русским программистом, который в основном работал на ассемблере. Он был фанатичен по поводу сохранения как можно большего количества байтов, потому что ранее он работал на системах с очень ограниченной памятью. «Это было для спутника. Лишь очень мало байтов, поэтому мы используем каждый байт для многих вещей». (суетливость, повторное использование байтов машинных инструкций для их числовых значений) Когда я попытался выяснить, какие типы спутников, я смог получить только «Орбитальный спутник. Для выведения на орбиту».

У него было еще две причуды: выпуклое зеркало, установленное над его монитором «Для того, чтобы узнать, кто смотрит», и случайный внезапный выход из кресла, чтобы сделать десять отжиманий. Последний объяснил это как «Компилятор обнаружил ошибку в коде. Это наказание».


87
Msgstr "Компилятор обнаружил ошибку в коде. Это наказание". !! Компания нашла тебя ... наказанием коллегам по работе!
Обучение

227
В Советской России программа собирает ВАС!
Crashworks

53
Когда я прочитал об ошибке компилятора «наказание», первое, о чем я подумал, было: «Добби пришлось гладить руки».
Грэм Перроу,

124
Я думаю, что программисты (включая меня) были бы намного лучше, если бы мы все делали 10 отжиманий каждый раз, когда компилятор обнаруживал ошибку в нашем коде. Это также может снизить вероятность тестирования при компиляции.
MikeyB

5
Этот парень звучит потрясающе. Но да, я не понимаю, как это должно улучшить размер кода.
Джалф

274

Мой худший

#define InterlockedIncrement(x) (x)++
#define InterlockedDecrement(x) (x)--

Я потратил два дня своей жизни на отслеживание некоторых многопоточных проблем с пересчетом COM, потому что какой-то идиот поместил это в заголовочный файл. Я не буду упоминать компанию, в которой я работал в то время.

Мораль этой истории? Если вы чего-то не понимаете, прочитайте документацию и узнайте об этом. Не просто заставьте это уйти.


146
@Joshua: Если вы запускаете этот код в многопоточной среде, вы можете просто непреднамеренно сделать это
1800 ИНФОРМАЦИЯ

11
«Если вы что-то не понимаете, прочитайте документацию и узнайте об этом. Не просто заставьте это уйти». - AMEN!
Пол Александр

2
@ 1800 Информация: я думаю, что вы просто потеряете голоса, поэтому я не могу вам их дать; p
wkf

5
Прости меня, как программиста не на C ++: главная проблема здесь в том, что поточно-безопасная функция преобразуется в не поточно-безопасную? Или что InterlockedIncrement ожидает указатель, так что теперь вы будете увеличивать указатель вместо того, на что он указывает? Или оба?
Тим Пицкер

38
Проблема в том, что InterlockedIncrement обычно является элементарной функцией, определенной в Windows API. Поэтому, когда люди вызывают InterlockedIncrement, они ожидают вызова функции, которая гарантированно будет выполнена атомарно. Вместо этого кто-то определил макрос с тем же именем, который оценивается как простой, не атомарный прирост
jalf 20.09.09

166
#define ever (;;)
for ever { 
   ...
}

52
Я предпочитаю <#define forever for (;;)>, чтобы вы могли писать <forever {...}>
paxdiablo

кто-то, кого я пошел в школу с потерянными оценками за НИКОГДА ... он был задушен, как это было в
учебнике

6
Разве предложение Пакса прямо не от K & R? Тем не менее, не стоит усилий, я бы сказал.
Джон Эриксон

Это на самом деле совсем не плохо. Я не использую for (;;)идиому, иначе я бы сразу добавил этот макрос в мой код.
AnT

1
@hayalci: В emacs lisp (и некоторых распространенных реализациях lisp) вы можете, (defmacro ever ())а затем(require 'cl (ever))
Joe D

145
#include <iostream>
#define System S s;s
#define public
#define static
#define void int
#define main(x) main()
struct F{void println(char* s){std::cout << s << std::endl;}};
struct S{F out;};

public static void main(String[] args) {
  System.out.println("Hello World!");
}

Задача: может ли кто-нибудь сделать это с меньшим количеством определений и структур? ;-)


19
Вы только что написали конвертер java-to-c! horray!
Андреас Петерссон

25
Отмечено как «оскорбительное». (Я ребенок!)
Анника Бэкстрем

40
Это либо ужасно красиво, либо красиво отвратительно.
Крис Латс

38
@Mark - он объявляет publicи static as nothing, void` как int, и main(x)как main(), так public static void main(String[] args)превращается в int main(). Затем Systemпревращается в S s;s, то есть System.out.println("Hello World!");превращается в то, S s; s.out.println("Hello World!");что вызывает printlnфункцию в Fструктуре в Sструктуре.
Крис Латс

2
Взгляните на это: mailcom.com/ioccc/chia/chia.c (скачайте и скомпилируйте его)
Роберто Бонваллет

130
#define private public

Я делал это раньше. Иногда вам просто нужно изменить переменную-член или переопределить функцию в каком-либо стороннем коде, который вы не можете изменить - и они не предоставили вам средство доступа.
Майкл Кристофик

30
это может быть полезно, даже если призраки объектного дизайна будут преследовать вас ночью.
Epaga

12
Хм, неопределенное поведение, простое нарушение правила одного определения, потенциальные различия в макете. Да, это победитель.
Дэвид Торнли

10
Таким образом, я могу получить доступ к частным и общедоступным материалам, но не к защищенным материалам, и не могу получить доступ к содержимому между classключевым словом и первым модификатором доступа.
Кен Блум

3
@Ken:#define class struct #define protected public
Яков Галка

107
#define if while

Это была шутка, на которой кто-то был


22
#define пока if будет еще коварнее.
StarBlue

7
Мы должны уточнить ваше заявление. Пострадавшие люди не нашли это забавным . :-)
Андрей Шепард

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

15
Это хорошая шутка, но она не скомпилируется, если есть какие-либо «другие» утверждения. Я обнаружил, что #define if (x) if (true) наиболее эффективен.
Графика Noob

32
Я всегда предпочитал #define sizeof (x) rand ()
Джон

106

Отвратительный

#define begin {
#define end }
/* and so on */

Серьезно, если вы хотите кодировать на Pascal, купите компилятор Pascal, не разрушайте прекрасный язык C.


45
Теперь вы задаетесь вопросом, какие языки я могу имитировать с помощью достаточно умного заголовочного файла.
Билл Ящерица

47
С не красиво. Это довольно некрасиво.
rlbond

27
Его красота заключается в его простоте. Говорят, что в нем есть вся скорость языка ассемблера в сочетании с читабельностью ... языка ассемблера :-) Я предпочитаю его раздутому C ++ (хотя я предпочитаю Java в своей повседневной работе из-за его огромной библиотеки).
paxdiablo

9
Нет, правда. Найдите оригинальный источник Борна для раковины Борна. Он сделал именно это, чтобы получить какой-то мерзкий беспорядок, похожий на АЛГОЛ.
RBerteig

3
#define DO for (int _i = 0; _i <= 1; ++ _ i) {if (_i == 1) //// LINE BREAK //// #define IF (cond); if (! (cond)) перерыв; } //// LINE BREAK //// DO printf ("a") IF (1 == 2);
Адриан Панасюк

93

«Архитектор», очень скромный парень, вы знаете тип, имел следующее:

#define retrun return

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


Я делаю эту опечатку так много, что я действительно обдумал это
Джошуа

4
скорее научите своего редактора автоматически заменять возврат в обратную сторону. Я совершил такие хакерские атаки с моим IRC-клиентом, по крайней мере
Tetha

1
Эй, я думаю, что раньше я тоже работал с этим «архитектором». В конце концов он был переклассифицирован старшим архитектором, когда ему нужно было успокоить свое эго.
BIBD

1
Я переопределил 'rn' на 'rm' в bash, потому что не мог набрать, а для чтения новостей 'rn' потребовалось 5 минут для запуска и подключения к серверу.
Мартин Беккет

2
Вы не могли просто открыть новый терминал (или переключиться на другой vt) и сделать killall rn?
Джо Д

69

Реальный мир? MSVC имеет макросы в minmax.h, вызываемые maxи min, которые вызывают ошибку компилятора каждый раз, когда я собираюсь использовать стандартную std::numeric_limits<T>::max()функцию.


2
Ах, да, именно поэтому у меня был специальный заголовок с восстановлением здравомыслия # undef's после MS-специфичных ...
Pontus Gagge

3
Решено с помощью (std :: numeric_limits <T> :: max) () Но да, довольно раздражает.
rlbond

36
Добавьте NOMINMAX в свойства вашего проекта в C / C ++ -> Preprocessor -> Preprocessor Definitions.
mattnewport

18
Эти макросы существовали в заголовках MS дольше, чем min, а max - в стандартной библиотеке C ++.
Ричард

4
Еще хуже, когда четыре другие ваши внешние зависимости также определяют свои собственные минимальные и максимальные значения различной степени сложности - от макросов с плохими скобками до хорошо написанных шаблонов, и одна из них просто делает невозможным быть неопределенным или иначе пропустить это ... В моей книге виноват только язык.
Роман Старков

58

Сочетание синтаксиса Паскаля и французских ключевых слов:

#define debut {
#define fin }
#define si if(
#define alors ){
#define sinon }else{
#define finsi }

36
#define zut_alors exit (-1)
MikeyB

4
Это потрясающе, и это заставило меня смеяться вслух. Итак, это в основном локализованная французская версия Basic, реализованная на C?
Бобби

56

У Раймонда Чена очень хорошие высказывания против использования макросов управления потоком . Его лучший пример - прямо из исходного кода оболочки Bourne:

ADDRESS alloc(nbytes)
    POS     nbytes;
{
    REG POS rbytes = round(nbytes+BYTESPERWORD,BYTESPERWORD);

    LOOP    INT     c=0;
    REG BLKPTR  p = blokp;
    REG BLKPTR  q;
    REP IF !busy(p)
        THEN    WHILE !busy(q = p->word) DO p->word = q->word OD
        IF ADR(q)-ADR(p) >= rbytes
        THEN    blokp = BLK(ADR(p)+rbytes);
            IF q > blokp
            THEN    blokp->word = p->word;
            FI
            p->word=BLK(Rcheat(blokp)|BUSY);
            return(ADR(p+1));
        FI
        FI
        q = p; p = BLK(Rcheat(p->word)&~BUSY);
    PER p>q ORF (c++)==0 DONE
    addblok(rbytes);
    POOL
}

2
Два момента: во-первых, эта паста испортила первоначальный отступ. И во-вторых, код выглядит хорошо для того, что он есть: Unix C 1970-х годов, страстный поклонник Algol-68. Если счастливчик может выразить себя в причудливом стиле, то почему Стив Борн не может? Конечно, кто-то, осужденный поддерживать его, кто не знает Алгол 68, может не оценить этот шанс расширить свои собственные вкусы.
Дариус Бэкон

Я думаю, что это может быть задумано Стивом Борном как шутка, а не как рекомендуемый стиль программирования
Мартин Беккет

2
Я видел if... else... elif... fiи case... esacраньше (на том языке, который Борн изобрел для sh), но loop... poolэто настоящая жемчужина.
Хоббс

54

Я хотел бы представить на конкурс камень под названием chaos-pp , который реализует функциональный язык с помощью макросов препроцессора.

Одним из примеров является вычисление 500-го числа Фибоначчи полностью препроцессором:

Исходный код перед препроцессором выглядит так:

int main(void) {
   printf
     ("The 500th Fibonacci number is "
      ORDER_PP(8stringize(8to_lit(8fib(8nat(5,0,0)))))
      ".\n");
   return 0;
}

При предварительной обработке файла мы получаем следующий результат (после довольно долгого ожидания):

$ cpp -I../inc fibonacci.c 2>/dev/null | tail
  return fib_iter(n, 0, 1);
}
# 63 "fibonacci.c"
int main(void) {
   printf
     ("The 500th Fibonacci number is "
      "139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125"
      ".\n");
   return 0;
}

1
Вы можете получить код из CVS и посмотреть. Некоторое время назад я наткнулся на некоторые подробности об этом в своем посте, когда наткнулся на него: bnpcs.blogspot.com/2009/02/… Если бы не проблема с отладкой полученного кода (проблема с очень длинными строками, если они генерируются таким «языком»), его можно было бы даже использовать в качестве практического генератора кода для C.
Andrew Y

Я могу только вообразить, что это
собирало целую

52

Непосредственно из Qt:

#define slots   /* */
#define signals /* */

Действительно приятно взаимодействовать с другими библиотеками, такими как boost :: сигналов ... В качестве примера, в Qt есть много других, которые создают забавно выглядящий код, такой как:

class X : public QObject {
   Q_OBJECT
private slots:
   //...
public signals:
   //...
};

И это C ++ ... но вдруг:

boost::signals::trackable

Больше не действителен C ++.


5
:) Так что это макрос, который ломает другие библиотеки даром. Это даже лучше, чем я ожидал :)
Дэвид Родригес - dribeas

38
Qt очень территориален и будет злобно атаковать другие библиотеки, которые пытаются занять его пространство имен :)
Джереми Фризнер,

21
К сожалению, Qt атакует библиотеки за пределами своего пространства имен с помощью макросов
David Rodríguez - dribeas

7
К счастью, boost :: signal2 исправил эту проблему;)
bdonlan

9
Используйте Q_SIGNALS и Q_SLOTS, если вы боитесь этого взаимодействия.
Тадеуш А. Кадлубовский,

50

В Windows.h много функций, которые злоупотребляют макросами.


MrValdez раздражен макросом GetObject, найденным в Windows.h

Макрос GetObject изменяет функцию GetObject () на GetObjectA () или GetObjectW () (в зависимости от того, скомпилирована ли сборка не в Юникоде и Юникоде соответственно)

MrValdez ненавидит необходимость делать перед строкой функции GetObject

#undef GetObject

Object *GetObject()

Альтернативой является изменение имени функции на что-то другое, например, GetGameObject ().


jdkoftinoff в комментариях прибил это: проблема в том, что все функции Windows API являются макросами.

Адам Розенфилд отметил, что проблемы могут быть исправлены путем определения NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX и т. Д. Перед включением windows.h для устранения проблем.


3
Вы можете подавить это, но # define'ing NOGDI перед включением windows.h, при условии, конечно, что вам не нужно использовать какую-либо из различных функций GDI. Существует множество других макросов, таких как WIN32_LEAN_AND_MEAN, NOMINMAX и т. Д., Которые подавляют определение или включение других вещей.
Адам Розенфилд

1
GetObject - это довольно общее имя функции. Возможно, вы могли бы использовать более описательное имя с учетом контекста, чтобы избежать столкновения. Тем не менее, это довольно злой макрос случай.
Страгер

1
Весьма досадно, что в win32 есть все макросы для преобразования имен API в FooA и FooW. У нас есть проблема с SendMessage.
i_am_jorf

6
Проблема в том, что все функции Windows API являются макросами. Один, который укусил меня, был GetTickCount (). Поскольку я делаю большую часть своего программирования вне окон, я нашел все определения в заголовках окон, а затем сделал свой собственный включаемый файл, который определил их все для проверки совместимости заранее.
jdkoftinoff

12
Я думаю, что у нас есть победитель. Это реальный мир, смехотворно плохая идея, и она затронула огромное количество невинных программистов. Кто бы ни был ответственен за этот драгоценный камень в Microsoft, следует считать военным преступником ... Самое приятное, что Microsoft дважды не думала об использовании таких удивительно распространенных имен, как GetObject, SendMessage или CreateWindow.
Джалф

45
#define return if (std::random(1000) < 2) throw std::exception(); else return

это просто так зло. Он случайный, что означает, что он все время срабатывает в разных местах, он изменяет оператор return, в котором обычно есть какой-то код, который может сам по себе потерпеть неудачу, он меняет невинно выглядящее ключевое слово, над которым вы никогда не будете подозревать, и использует исключение из стандартного пространства, так что вы не будете пытаться искать в своих источниках, чтобы найти его источник. Просто великолепно.


4
Только что протестировал этот, по крайней мере, он не компилируется по умолчанию из-за отсутствия включения include для random, и тогда он красный. Однако, если вы случайно включили включение, VC ++ 2010 помечает его как ключевое слово и не отображает всплывающую подсказку о расширении макросов, так что в IDE это не поможет: - /
OregonGhost

Я люблю это! Чистый гений. Представьте, как хорошо вы можете выглядеть, когда вы «отлаживаете» это приложение, когда никто другой не смог.
Брайс

36

Мы с коллегой нашли эти два драгоценных камня в нашем коде для потоковой передачи объектов. Эти макросы были созданы в КАЖДОМ ОДНОМ файле класса, который выполнял потоковую передачу. Мало того, что этот отвратительный код извергался по всей нашей кодовой базе, когда мы обратились к первоначальному автору по этому поводу, он написал 7-страничную статью в нашей внутренней вики, защищающую это как единственный возможный способ выполнить то, что он пытался сделать здесь.

Излишне говорить, что с тех пор он был переработан и больше не используется в нашей кодовой базе.

Не отбрасывайте выделенные ключевые слова. Это ВСЕ макрос

#define DECLARE_MODIFICATION_REQUEST_PACKET( T )                                                \
namespace NameSpace                                                                     \
{                                                                                       \
                                                                                        \
class T##ElementModificationRequestPacket;                                                          \
}                                                                                       \
                                                                                        \
DECLARE_STREAMING_TEMPLATES( IMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase )    \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( NameSpace::ElementModificationRequestPacket<T> )     \
DECLARE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )      \
                                                                                        \
namespace NameSpace {                                                                   \
class DLLIMPEXP_COMMON T##ModificationRequestPacket : public ElementModificationRequestPacket<T>\
{                                                                                       \
public:                                                                                 \
    T##ModificationRequestPacket( NetBase * pParent )                                   \
    : ElementModificationRequestPacket<T>( pParent ), m_Gen() {}                            \
                                                                                        \
    T##ModificationRequestPacket( NetBase * pParent,                                    \
                            Action          eAction,                                    \
                            const T &   rT )                                            \
    : ElementModificationRequestPacket<T>( pParent, eAction, rT ), m_Gen() {}               \
                                                                                        \
    T##ModificationRequestPacket( const T##ModificationRequestPacket & rhs )                        \
    : ElementModificationRequestPacket<T>( rhs ), m_Gen() {}                                \
                                                                                        \
    virtual                     ~T##ModificationRequestPacket( void ) {}                        \
                                                                                        \
    virtual Uint32          GetPacketTypeID( void ) const                           \
    {                                                                                   \
        return Net::T##_Modification_REQUEST_PACKET;                                        \
    }                                                                                   \
                                                                                        \
    virtual OtherNameSpace::ClassID GetClassID ( void ) const                           \
    {                                                                                   \
        return OtherNameSpace::NetBase::GenerateHeader( OtherNameSpace::ID__LICENSING,  \
                                                         Net::T##_Modification_REQUEST_PACKET );    \
    }                                                                                   \
                                                                                        \
    virtual T##ModificationRequestPacket * Create( void ) const                             \
    { return new T##ModificationRequestPacket( m_pParent ); }                                   \
                                                                                        \
    T##ModificationRequestPacket() {}                                                           \
                                                                                        \
protected:                                                                              \
    OtherNameSpace::ObjectAutogeneration<T##ModificationRequestPacket> m_Gen;                       \
                                                                                        \
    friend class OtherNameSpace::StreamingBase::StreamingClassInfoT<T##ModificationRequestPacket >;                     \
    OtherNameSpace::StreamingBase::Streaming<T##ModificationRequestPacket, ElementModificationRequestPacket<T> >    m_Stream;   \
                                                                                        \
};                                                                                      \
}                                                                                       \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )            \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )            \
typedef  ThirdNameSpace::BroadcasterT<const T##ModificationRequestPacket>  T##ModifiedBroadcaster;



#define IMPLEMENT_MODIFICATION_REQUEST_PACKET( T )                                                                  \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( NameSpace::ElementModificationRequestPacket<T> )                         \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )        \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )        \
INSTANTIATE_STREAMING_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase ) \
INSTANTIATE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )

Обновление (17 декабря 2009 г.):

Больше хороших новостей об этом отвратительном авторе макросов. По состоянию на август сотрудник, ответственный за это чудовище, был уволен.


3
он, очевидно, никогда не слышал: «Во-первых, отладка вдвое сложнее, чем писать код. Поэтому, если вы пишете код настолько умно, насколько это возможно, вы, по определению, недостаточно умны для его отладки». -Брайан В. Керниган
Тревор Бойд Смит

33

Я сделал следующее сам, и я думаю, что чему-то научился.

Примерно в 1992 году я написал небольшой переводчик Lisp. Это не было реализовано в обычном C, но в интерпретируемом C-подобном языке. Этот C-подобный язык использовал стандартный препроцессор C, хотя.

Разумеется, интерпретатор Lisp содержал функции car , которые используются в Lisp для возврата первого элемента в списке, и cdr , который возвращает остальную часть списка. Они были реализованы так:

LISPID car(LISPID id) {
    CHECK_CONS("car", 1, id);
    return cons_cars[id - CONS_OFFSET];
} /* car */

LISPID cdr(LISPID id) {
    CHECK_CONS("cdr", 1, id);
    return cons_cdrs[id - CONS_OFFSET];
} /* cdr */

(Данные были сохранены в массивах, поскольку не было структур. CONS_OFFSET - это константа 1000.)

car и cdr часто используются в Лиспе и являются короткими, и поскольку вызовы функций не были очень быстрыми в языке реализации, я оптимизировал свой код, реализовав эти две функции Лиспа в виде макросов:

#define car(id) (CHECK_CONS("car", 1, (id)), cons_cars[(id) - CONS_OFFSET])
#define cdr(id) (CHECK_CONS("car", 1, (id)), cons_cdrs[(id) - CONS_OFFSET])

CHECK_CONS проверяет, что его аргумент на самом деле является списком, и поскольку этот аргумент также часто используется в интерпретаторе и является коротким, я написал его тоже как макрос:

#define CHECK_CONS(fun, pos, arg)   \
    (!IS_CONS(arg) ?        \
        LISP_ERROR("Arg " + pos + " to " + fun +    \
                   " must be a list: " + lispid2string(arg)) : 0)

IS_CONS и LISP_ERROR также часто использовались, поэтому я тоже превратил их в макросы:

#define IS_CONS(id) \
    (   intp(id) && (id) >= CONS_OFFSET     \
     && ((id) - CONS_OFFSET) < sizeof(cons_cars))

#define LISP_ERROR(str)     (throw((str) + "\n"))

Кажется разумным?

Но тогда почему вся система рухнула на этой строке:

id2 = car(car(car(car((id1))));

Я долго работал над поиском проблемы, пока, наконец, не проверил, к чему эта короткая строка была расширена препроцессором. Она была расширена до строки из 31370 символов, которую я здесь разделил на строки (502 из них) для ясности:

id2 = ((!(intp( (((!(intp( (((!(intp( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
&& ( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) && ( (((!(intp(
(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) >= 1000 && ((
(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (((!(intp( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1))
&& ( (id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars))

18
I optimized my code by implementing those [..] functions as macros- знаменитые последние слова ...
BlueRaja - Дэнни Пфлюгофт

3
Я совершал подобные злоупотребления в ранних версиях моего интерпретатора Postscript. Push и pop были функциями, которые были настолько важны, что они должны были быть макросами . Но составление выражения, включающего более одного из них, приводит к неопределенному поведению. Неопределенное поведение обнаруживается только при компиляции в -O3. И в -O3 версии функций были бы встроены в любом случае.
Люзер Дрог

29

Однажды мне пришлось портировать приложение C с unix на windows, специфическая природа которого останется безымянной, чтобы защитить виновных. Парень, который написал это, был профессором, не привыкшим писать производственный код, и явно пришел к Си с какого-то другого языка. Бывает и так, что английский не был его родным языком, хотя в стране, из которой он приехал, большинство людей говорят на нем довольно хорошо.

Его приложение интенсивно использовало препроцессор для преобразования языка Си в формат, который он мог лучше понять. Но макросы, которые он использовал чаще всего, были определены в заголовочном файле с именем «Thing.h» (серьезно), который включал следующее:

#define I  Any void_me
#define thou  Any void_thee
#define iam(klas)  klas me = (klas) void_me
#define thouart(klas)  klas thee = (klas) void_thee
#define my  me ->
#define thy  thee ->
#define his  him ->
#define our  my methods ->
#define your  thy methods ->

... который он затем использовал, чтобы написать чудовища, подобные следующим:

void Thing_setName (I, const char *name) {
iam (Thing);
if (name != my name) {
    Melder_free (my name);
    my name = Melder_wcsdup (name);
    }
    our nameChanged (me);
}

void Thing_overrideClass (I, void *klas) {
iam (Thing);
my methods = (Thing_Table)klas;
if (! ((Thing_Table) klas) -> destroy)
    ((Thing_Table) klas) -> _initialize (klas);
}

Весь проект (~ 60 000 LOC) был написан в похожем стиле - марко ад, странные имена, древнеанглийский жаргон и т. Д. К счастью, мы смогли выбросить код, так как я нашел библиотеку OSS, которая выполняла тот же алгоритм десятки раз быстрее.

(Я скопировал и отредактировал этот ответ, который я изначально сделал на этот вопрос ).


3
Я довольно очарован собственниками и архаичным английским, хотя я согласен, что код выглядит ужасно.
Дариус Бэкон

27

Худшее, с чем я когда-либо сталкивался, было в продукте, содержащем набор исполняемых файлов, где назначенный технический лидер не определил библиотеки.

Вместо этого у него были наборы файлов, которые использовались в нескольких папках Visual Source Safe. Затем он понял, что они должны вести себя немного по-разному для каждого приложения.

Есть несколько шагов рефакторинга, которые вы можете применить здесь.

Вместо этого он использовал #ifdefs

   void DisplayLoadError()
   {
   #if defined __TIMETABLE_EDITOR
   MessageBox("Timetable Editor failed to load the correct timetable", MB_ERROR);
   #else if defined __SCHEDULESET_EDITOR
   MessageBox("Schedule Set Editor faied to load the correct Schedule Set", MB_ERROR);
   #else if defined __ROSTER_EDITOR
   MessageBox("Roster Editor failed to load the correct Roster", MB_ERROR);
   #endif
   }

17

Использование препроцессора LINE для генерации уникального идентификатора для сообщений, передаваемых по сети:

NetworkMessages.h

#define MSG_LOGIN  __LINE__
#define MSG_LOGOUT __LINE__
#define MSG_CHAT   __LINE__

Это пример, где макрос действительно был лучше, чем немароксальное решение:

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

Кроме того, проще добавлять новые сообщения, просто добавив сообщение в источник.

Недостатком этой ситуации является то, что файл должен быть включен во весь код, который использует сообщения. Время компиляции будет увеличиваться всякий раз, когда сообщение редактируется.


8
И версии могут быть несовместимы друг с другом (не хорошо!). Почему перечисления не хватает?
Страгер

И у этого, и у Enum точно такая же проблема несовместимости.
MrValdez

17
Теперь я прихожу и сортирую #defines ... и протокол меняется. Или я получаю религию Doxygen и документирую все коды сообщений и изменения протокола. По крайней мере, перечисление стабильно при последнем изменении.
RBerteig

3
@MrValdez, хранить порядок перечислений менее строго, чем сохранять определения в тех же строках относительно начала файла.
Петерчен

Я знаю, что это старый пост, но это вообще работает? Я имею в виду, что #define просто заменит константы сообщения на LINE, и только тогда LINE будет расширен до номера строки, поэтому каждый раз, когда мы используем одну и ту же константу в разных строках, она будет меняться (до текущего номера строки)?
XzKto

16

Один довольно плохой пример:

#ifdef __cplusplus
#define class _vclass
#endif

Это позволяет структуре C, содержащей переменную-член, вызываемую classдля обработки компилятором C ++. Есть два заголовка с этой конструкцией в нем; один из них также содержит '#undef class' в конце, а другой нет.


1
Вот почему Objective-C использует @classвместо class.

14

За один год Международного конкурса кодирования с запутанным кодом была запись, где вся программа была:

P

С условием, что вы можете определить Pв make-файле любую программу, какую захотите.

Насколько я помню, он выиграл в одной из категорий, и в следующем году появилось правило, запрещающее такой стиль входа.

(Изменить: через шесть месяцев или что-то ... Я уверен, что "Нет IOCCC" не было в основном вопрос, когда я написал это ...)


12

Мне было скучно однажды, и я играл с блоками в Objective-C ...

#define Lambda(var, body) [^ id(id (var)) { return (body);} copy]
#define Call(f, arg) ((id(^)(id))(f))(arg)
#define Int(num) [NSNumber numberWithInteger:(num)]
#define Mult(a, b) Int([(a) integerValue] * [(b) integerValue])
#define Add(a, b) Int([(a) integerValue] + [(b) integerValue])
#define Sub1(n) Int([(n) integerValue] - 1)
#define Add1(n) Int([(n) integerValue] + 1)
#define If(cond, thenblock, elseblock) ([(cond) integerValue] ? (thenblock) : (elseblock))
#define Cons(car, cdr_) [[ConsType alloc] initWithCar:(car) cdr:(cdr_)]
#define Car(list) [(list) car]
#define Cdr(list) [(list) cdr]
#define Define(var, value) id var = (value)
#define Nullq(value) Int(value == nil)

позволяет "интересные" вещи, такие как:

Define(Y, Lambda(f, Call(Lambda(x, Call(x, x)),
                         Lambda(x, Call(f, Lambda(y, Call(Call(x, x), y)))))));
Define(AlmostTotal, Lambda(f, Lambda(list, If(Nullq(list), Int(0),
                                              Add(Car(list), Call(f, Cdr(list)))))));
Define(Total, Call(Y, AlmostTotal));
Print(Call(Total, Cons(Int(4), Cons(Int(5), Cons(Int(8), nil)))));

(некоторые определения функций и классов не показаны для краткости)


«Мне было скучно однажды», известный разработчик, последние слова :)
Ричард Дж. Росс III,

11

Худшее, что я видел, было неиспользованием :-)

Кто-то написал функцию strcpy (я думаю, что это было ... более 10 лет назад) внутри метода (потому что он не хотел накладных расходов на вызов strcpy ... sigh).

Они поняли, что для японских символов это не сработает, поэтому в начале добавили «если», чтобы сделать ASCII или Unicode. На тот момент код был длиной около экрана ... вероятно, это нарушало целостность кэша и стирало его предполагаемую экономию для встраивания кода.

Код был идентичным, за исключением типов (поэтому следовало использовать макрос).

Конечно, написанная ими strcpy была намного намного медленнее, чем вручную настроенный ассемблер, который был в стандартной библиотеке ...

Конечно, если бы они сделали все это как макрос, его можно было бы заменить вызовом strcpy ...

Конечно, я ухожу из компании (не напрямую из-за этого ...)


The code was identical save for the types (so should have used a macro).Нет, он должен был использовать шаблон.
BlueRaja - Дэнни Пфлюгофт

1
Он должен был использовать встроенный strcpy! (и это был код C, а не C ++, поэтому нет шаблонов) :-P
TofuBeer

Преждевременная оптимизация - корень всего зла.
Юбер Карио

11

Обязательный

#define FOR  for

и

#define ONE  1
#define TWO  2
...

Кто знал?


5
Но-но-но НЕТ ЛИТЕРАТОВ В КОДЕКЕ! ;)
Бернард

они по-прежнему являются литералами mon, должны называть их по назначению / намерению, а не по альтернативному символу Код на языке COBOL, о котором я слышал, сделал переменную 5 = 5, а затем получил код, говорящий о наборе 5 = 10 ... люди были очень удивлены, когда сделали вар + 5 и получили вар + 10.
Грег Домжан

1
Никогда не слышал об этом с Коболом, только с Фортраном. Кобол, конечно, имеет в качестве зарезервированных слов нули, нули и нули, причем все они означают то же самое, что и 0.
Дэвид Торнли

Гораздо лучше, чем "#define ONE 0". Если вы хотите посмеяться, поищите это в Интернете и удивитесь ненулевому количеству хитов.
Reuben

11
#define TRUE 0 // dumbass

Человек, который сделал это, объяснил себя несколько лет спустя - большинство (если не все) библиотечные функции C возвращают 0 как признак того, что все прошло хорошо. Итак, он хотел иметь возможность писать код вроде:

if (memcpy(buffer, packet, BUFFER_SIZE) == TRUE) {
; // rape that packet
}

Излишне говорить, что никто в нашей команде (тестер или разработчик) никогда не осмеливался взглянуть на его код снова.


1
я обвиняю функции библиотеки C в том, что она заставляет 0 «все в порядке»: P
RCIX

6
Почему бы не объявить что-то подобное #define FLAG_SUCCESS 0?
Пион

11

Я поддерживаю код с gotos в макросах. Таким образом, функция будет иметь метку в конце, но не будет видимого перехода в коде функции. Что еще хуже, макрос находится в конце других операторов, как правило, за кадром, если вы не прокручиваете горизонтально.

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

void SomeFunction() 
{ 
    SomeLongFunctionName(ParamOne, ParamTwo, ParamThree, ParamFour); CHECK_ERROR  
    //SomeOtherCode  
    Cleanup:    
   //Cleanup code  
}

Что еще хуже, когда макросы скрывают как gotoоператоры, так и определения целевых меток. Абсолютно волшебство.
Reuben

Я страдал от этого - но макросы выглядели как вызовы функций.
Джонатан Леффлер

10
#include <iostream>
#define public_static_void_main(x) int main()
#define System_out_println(x) std::cout << x << std::endl

public_static_void_main(String[] args) {
  System_out_println("Hello World!");
}

3
И ВЫ хотели написать время выполнения. Посмотрите, сколько времени я сэкономил!
Бернард

4
@Trevor: Да ... умные все еще делают Java вместо этого. бежит за прикрытием
Майкл Майерс

Если вы поставите [] после args вместо before и "#define String int argc, char *", он скомпилируется (к сожалению).
Адам Розенфилд

16
Мне больше нравится другой. Этот показывает что-то похожее на Java, написанное с несколькими макросами. Другой показывает точную Java, написанную с множеством хитрых макросов и структур с членами-функциями. Первый был дешевой шуткой, а второй - продуманной и продуманной шуткой.
Крис Латс

10

Одноклассник, который не смог понять правила о магических числах:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1


9

ASA - http://www.ingber.com/#ASA

Вы действительно должны загрузить это, чтобы оценить это. Весь рабочий процесс определяется макросами. Это совершенно нечитаемо. Например -

 if (asa_open == FALSE) {
asa_open = TRUE;
++number_asa_open;
#if ASA_PRINT
if (number_asa_open == 1) {
  /* open the output file */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
#else
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "w");
#endif
  }
#else /* USER_ASA_OUT */
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (ASA_OUT, "a");
#else
    ptr_asa_out = fopen (ASA_OUT, "w");
#endif
  }
#endif /* USER_ASA_OUT */
} else {
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
  fprintf (ptr_asa_out, "\n\n\t\t number_asa_open = %d\n",
           number_asa_open);
}
#endif /* ASA_PRINT */
} else {
++recursive_asa_open;
#if ASA_PRINT
if (recursive_asa_open == 1) {
  /* open the output file */
#if ASA_SAVE
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
#else /* ASA_SAVE */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {

и т. д.

И это только настройка параметров. вся программа такая.


2
Боже мой ... Думаю, у меня кружится голова.
Майкл Фукаракис
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.