Які найгірші макроси / зловживання перед процесором у реальному світі, які ви коли-небудь стикалися?


176

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

Додайте короткий фрагмент чи розповідь, якщо це дійсно цікаво. Мета - навчити чогось, а не завжди говорити людям "ніколи не використовуй макроси".


ps: Раніше я використовував макроси ... але зазвичай я їх позбавляю зрештою, коли маю "справжнє" рішення (навіть якщо реальне рішення вкладене, то воно стає схожим на макрос).


Бонус: Наведіть приклад, коли макрос справді був кращим, ніж немакрос.

Пов'язане запитання: Коли корисні макроси C ++?


+1 за привернення уваги до бурхливих зловживань, які я зазнав від рук Макроса.
i_am_jorf

37
#define true false // щаслива налагодження :)
n0rd

Вікі спільноти означає, що ніхто не здобуде (і не втратить) репутації від голосів "вгору / вниз" з цього питання або його відповідей. Багато людей розглядають подібні питання як дешеві та прості способи здобути репутацію, тому, якщо ви позначаєте це як вікі спільноти, люди мають меншу ймовірність зірвати форму та закрити її.
Graeme Perrow

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
"Компілятор знайшов помилку в коді. Це покарання". !! Компанія знайшла вас ... покарання колегам!
Навчання

227
У Радянській Росії програма збирає ВАС!
Crashworks

53
Коли я читав про помилку компілятора «покарання», перше, що мені спало на думку, було «Доббі довелося гладити руки».
Graeme Perrow

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

5
Цей хлопець звучить приголомшливо. Але так, я не бачу, як це повинно покращити розмір коду.
jalf

274

Моє найгірше:

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

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

Мораль цієї історії? Якщо ви щось не розумієте, прочитайте документацію та дізнайтеся про неї. Не просто змушуйте його піти.


146
@Joshua: Якщо ви запускаєте цей код у багатопотоковому середовищі, ви можете ненавмисно зробити це
1800 ІНФОРМАЦІЯ

11
"Якщо ви чогось не розумієте, прочитайте документацію та дізнайтеся про неї. Не змушуйте її просто відійти". - АМЕН!
Пол Олександр

2
@ 1800 Інформація: Я думаю, що ви просто втратите голоси, тому я не можу вам надати жодного; p
wkf

5
Пробачте мене як програміста, що не стосується C ++: Чи головна проблема тут у тому, що функція безпечної передачі потоків перетворюється на безпечну функцію, яка не є потоком? Або що InterlockedIncrement очікує вказівник, тож тепер ви збільшите покажчик замість того, на що він вказує? Або обоє?
Тім Піцкер

38
Проблема полягає в тому, що InterlockedIncrement зазвичай є атомною функцією, визначеною в API API Windows. Тож, коли люди викликають InterlockedIncrement, вони сподіваються запустити функцію, яка гарантовано виконується атомно. Натомість хтось визначив макрос з такою ж назвою, який оцінює звичайний
неатомний

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

52
Я віддаю перевагу <#define forever for (;;)>, щоб ви могли писати <назавжди {...}>
paxdiablo

хтось, я ходив до школи з втраченими балами за КОГО-небудь річ ... він захлинувся, як це було в підручнику :-)
TofuBeer

6
Чи не пропозиція Пакса прямо з K&R? Все-таки, не варте зусиль, я б сказав.
Джон Ерісон

Це насправді зовсім не погано. Я не використовую for (;;)ідіому, інакше я негайно додав би цей макрос до свого коду.
090 року

1
@hayalci: У emacs lisp (і деякі поширені реалізації lisp) ви могли б (defmacro ever ())і потім(require 'cl (ever))
Джо Д

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! жах!
Андреас Петерсон

25
Повідомляється як "образливий". (Я дитина!)
Annika Backstrom

40
Це або жахливо красиво, або гарно огидно.
Кріс Лутц

38
@Mark - Він оголошує publicі static as nothing, недійсним як 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функцію в Fstru в Sструктурі.
Кріс Лутц

2
Подивіться на це: mailcom.com/ioccc/chia/chia.c (завантажте та компілюйте)
Роберто Бонвальлет

130
#define private public

Я робив це раніше. Іноді вам просто потрібно змінити змінну члена або змінити функцію в якомусь сторонньому коді, який ви не можете змінити - і вони не надали вам доступ.
Михайло Кристофік

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

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

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

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

107
#define if while

Це був жарт, розіграний на когось, його не виявили забавним


22
#define в той час, якби було ще підступніше.
starblue

7
Ми повинні уточнити вашу заяву. Люди, які постраждали, не знайшли забавки . :-)
Андрій Пастух

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

15
Це гарна хитрість, але вона не компілюється, якщо є якісь ще "заяви". Я виявив, що #define, якщо (x), якщо (правда) є найбільш ефективним.
Графіка Noob

32
Я завжди вважав за краще #define SizeOf (х) рандів ()
Jon

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); якщо (! (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?
Джо D

69

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


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

3
Вирішено з (std :: numeric_limits <T> :: max) () Але так, це дуже дратує.
rlbond

36
Додайте NOMINMAX до своїх властивостей проекту в розділі C / C ++ -> Preprocessor -> Preprocessor Definitions.
mattnewport

18
Ці макроси існували в заголовках MS довше ніж min та max були у стандартній бібліотеці C ++.
Річард

4
Ще гірше, коли чотири ваші інші зовнішні залежності також визначають мінімальну / макс свою власну, різного ступеня придатності, починаючи від макросів з поганим дужкою до добре написаних шаблонів, і одна з них просто повинна унеможливити неможливість визначення або інакше пропустити ці ... У моїй книзі мова на 50% винна.
Роман Старков

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
Два моменти: один, ця паста зіпсувала початковий відступ. І друге, код виглядає чудово, що це таке: 1970-х Unix C запальним вентилятором Algol-68. Якщо _що щасливий жорсткий може виразити себе у вигадливому стилі, то чому не може Стів Борн? Звичайно, хтось, засуджений на підтримку цього, хто не знає Algol 68, може не оцінити цей шанс розширити власні смаки.
Дарій Бекон

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

2
Я бачив if... else... elif... fiі case... esacраніше (тією самою мовою, яку Борн вигадав для ш), але 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

Я просто можу уявити, що потрібно складати вічно
Пол Фульц II

52

Безпосередньо з Qt:

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

Дійсно приємно взаємодіяти з іншими libs як boost :: сигналами ... Просто приклад, у Qt є багато інших, які створюють смішний вигляд коду, наприклад:

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

І це C ++ ... але раптом:

boost::signals::trackable

Більше не діє C ++.


5
:) Отже, це макрос, який порушує інші бібліотеки ні за що. Це навіть краще, ніж я очікував :)
Девід Родрігес - дрибес

38
Qt дуже територіальний і жорстоко атакує інші бібліотеки, які намагаються зайняти його простір імен :)
Jeremy Friesner

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 () (залежно від того, якщо збірка компілюється у не-unicode та unicode відповідно)

MrValdez ненавидить робити перед функцією GetObject

#undef GetObject

Object *GetObject()

Альтернативою є зміна назви функції на щось інше, як GetGameObject ()


jdkoftinoff в коментарях прибив це: проблема полягає в тому, що всі функції API Windows є макросами.

Адам Розенфілд зазначив, що проблеми можна усунути, визначивши NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX тощо, перш ніж включити windows.h для усунення проблем.


3
Ви можете придушити це, але # визначити NOGDI, перш ніж включати windows.h, за умови, що вам не потрібно використовувати жодну з різних функцій GDI. Існує маса інших макросів, таких як WIN32_LEAN_AND_MEAN, NOMINMAX тощо, які пригнічують інші речі від визначення або включення.
Адам Розенфілд

1
GetObject - це досить загальна назва функції. Можливо, ви могли б використати більш описову назву з огляду на контекст, щоб уникнути зіткнення. Однак це досить злий макросклад.
страгер

1
Дуже дратує, що win32 має всі макроси для перетворення імен API в FooA і FooW. У нас проблема з SendMessage.
i_am_jorf

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

12
Я думаю, що у нас є переможець. Це в реальному світі, це смішно погана ідея, і це торкнулося величезної кількості невинних програмістів. Хто несе відповідальність за цей дорогоцінний камінь у Microsoft, слід вважати військовим злочинцем ... Найкраще, що Microsoft двічі не замислювалася над використанням таких дивовижних загальних імен, як GetObject, SendMessage або CreateWindow.
jalf

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

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


4
Щойно перевірений цей, принаймні він не компілюється за замовчуванням через відсутність включення для випадкових випадків, і він є червоним витками тоді. Якщо у вас включено включення випадково, 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 році або близько того я написав маленького перекладача Ліспа. Він не був реалізований у звичайному мові 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 часто використовуються в Lisp, і вони короткі, а оскільки виклики функцій не були дуже швидкими мовою реалізації, я оптимізував свій код, реалізуючи ці дві функції Lisp як макроси:

#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 - Danny Pflughoeft

3
Я вчинив подібні зловживання в ранніх версіях мого перекладача Postscript. Push and pop були функціями, які були настільки важливими, що вони повинні бути макросами . Але складання виразу, що включає більше одного з них, призводить до невизначеної поведінки. Невизначена поведінка виявляється лише при складанні на -O3. І при -O3 версії функцій все одно були б накреслені.
luser droog

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

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

Натомість у нього були набори файлів, які спільно використовувались у кількох папках Safe 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
І версії можуть бути несумісними між собою (не добре!). Чому переліків не вистачало?
страгер

І це, і Енум мають абсолютно таку ж проблему несумісності.
Містер Вальдес

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

3
@MrValdez, менш обмежувати утримувати блок перерахунків в порядку, ніж зберігати визначені в тих же рядках щодо запуску файлу.
peterchen

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

16

Один досить поганий приклад:

#ifdef __cplusplus
#define class _vclass
#endif

Це дозволяє структурі C, яка містить змінну члена, викликану, classщоб обробляти компілятор C ++. У ній є два заголовки з цією конструкцією; одна з них містить також "#undef class" наприкінці, а інша - ні.


1
Ось чому Objective-C використовує @classзамість class.

14

В один рік Міжнародного конкурсу з прихованого кодування C був запис, де вся програма була:

P

За умови, що ви можете визначити Pв makefile, що це будь-яка програма, яку ви хотіли.

Як я пам’ятаю, вона виграла в одній із категорій, а наступного року з'явилося правило, забороняючи цей стиль вступу.

(Редагувати: через півроку чи щось таке ... Я впевнений, що "Ніякий МОКК" не був головним питанням, коли я писав це ...


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 ... зітхання).

Вони зрозуміли, що це не буде працювати для японських символів, тому вони додали "якщо" на початку робити ASCII або Unicode. У той момент код був приблизно на екрані ... ймовірно, вбивство кеш-когерентності та стирання його передбачувані заощадження для вбудовування коду.

Код був ідентичним збереженням для типів (тому мав використовувати макрос).

Звичайно, strcpy, який вони написали, був набагато набагато повільніше, ніж налаштований вручну асемблер, який був у стандартній бібліотеці ...

Звичайно, якби вони тільки що зробили це як макрос, його можна було б замінити викликом strcpy ...

Звичайно, я покинув компанію (не безпосередньо через це ...)


The code was identical save for the types (so should have used a macro).Ні, він повинен був використовувати шаблон.
BlueRaja - Danny Pflughoeft

1
Він повинен був використовувати вбудований strcpy! (а це був код C, а не C ++, тому немає шаблонів) :-P
TofuBeer

Передчасна оптимізація - корінь усього зла.
Хуберт Каріо

11

Обов’язковий

#define FOR  for

і

#define ONE  1
#define TWO  2
...

Хто знав?


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

вони все ще є літералами пн, повинні називати їх за призначенням / наміром, а не альтернативним символом. Код COBOL, про який я чув, вони зробили змінну 5 = 5, потім пізніше було встановлено код 5: 10 ... люди, де реально здивувались, коли зробили var + 5 і отримали var + 10.
Грег Дом'ян,

1
Ніколи не чув про це з COBOL, тільки з FORTRAN. У COBOL, звичайно, ZERO, ZEROS та ZEROES є зарезервованими словами, всі вони означають те саме, що і 0.
Девід Торнлі,

Набагато краще, ніж "#define ONE 0". Якщо ви хочете посміхнутися, пошукайте в Інтернеті і дивуйтеся не нульовій кількості звернень.
reuben

11
#define TRUE 0 // dumbass

Людина, яка зробила це, пояснила себе через кілька років - більшість (якщо не всі) функції бібліотеки С повертають 0 як свідчення того, що все пішло добре. Отже, він хотів вміти писати код на зразок:

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

Потрібно сказати, що ніхто з нашої команди (тестер чи розробник) ніколи не наважився знову переглянути його код.


1
Я звинувачую функції бібліотеки С за те, що 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. працює на обкладинку
Майкл Майєрс

Якщо ви поставите [] після аргументів замість до, і "#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.