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

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

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


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


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

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


person Community    schedule 17.03.2009    source источник
comment
+1 за привлечение внимания к безудержному насилию, которому я подвергся от рук Макросов.   -  person i_am_jorf    schedule 17.03.2009
comment
#define true false // удачной отладки :)   -  person n0rd    schedule 17.03.2009
comment
Вики Сообщества означает, что никто не получит (или не потеряет) репутацию в результате голосования «за» или «против» по ​​этому вопросу или ответам на него. Многие люди рассматривают подобные вопросы как дешевый и простой способ заработать репутацию, поэтому, если вы отметите его как вики сообщества, люди с меньшей вероятностью потеряют форму и закроют его.   -  person Graeme Perrow    schedule 19.03.2009
comment
люди, скорее всего, согнутся и закроют ее: вы подразумеваете, что не хотите, чтобы какой-либо юмористический / забавный контент при переполнении стека?   -  person Trevor Boyd Smith    schedule 19.03.2009
comment
Я ничего не сказал о том, чего я хочу или не хочу. Но такие вопросы, которые не отмечены CW, часто быстро закрываются. Если они отмечены CW, они, как правило, проживут немного дольше.   -  person Graeme Perrow    schedule 19.03.2009
comment
Это не настоящий мир, но я думаю, что он заслуживает (не) почетного упоминания: 99-bottles-of-beer.net/language-c-c ++ - preprocessor-115.html   -  person Grant Peters    schedule 16.08.2009
comment
Вкратце, препроцессор является частью языка и, следовательно, не является плохим / неправильным в использовании, как и все остальное.   -  person Mr. Boy    schedule 01.04.2010
comment
Вы имеете в виду, что IOCCC не является частью реального мира?   -  person Timwi    schedule 17.09.2010


Ответы (70)


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

#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, у него есть синтаксическая окраска!)

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

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

person Community    schedule 17.03.2009
comment
Я не понимаю, какую пользу принесет вам этот макрос; компилятор просто вернет им символы, и если он не напишет какой-нибудь полезный quine, размер кода не будет иметь значения. - person Ryan Fox; 17.03.2009
comment
Вам не хватает ключевого слова "возврат" в расширении? Думаю, я ожидал, что это ужас будет '#define RETURN (x) return (x);}'. - person Jonathan Leffler; 17.03.2009
comment
Компилятор обнаружил ошибку в коде. Это наказание. !! Компания вас нашла ... наказание коллегам! - person Learning; 17.03.2009
comment
В Советской России программу компилируют ВЫ! - person Crashworks; 17.03.2009
comment
Бу- Вай- Кто-. Это противно. - person Bernard; 17.03.2009
comment
Не случайно ли его звали Питр? - person Adrian Grigore; 17.03.2009
comment
Когда я прочитал о наказании за ошибки компилятора, первое, о чем я подумал, это то, что Добби пришлось погладить руки. - person Graeme Perrow; 19.03.2009
comment
Я думаю, что это стоит отредактировать ... оператор определения неверен. В остальном чистая радость! - person jpinto3912; 03.06.2009
comment
В случае, если кто-то считает, что это был одинокий сумасшедший программист, я также видел очень похожую вещь, сделанную для операторов возврата и фигурных скобок. Что еще хуже, макросы не были названы так, чтобы было очевидно, что действительно произошел возврат! - person iammichael; 25.06.2009
comment
Я думаю, что программисты (включая меня) были бы намного лучше, если бы мы все делали по 10 отжиманий каждый раз, когда компилятор обнаруживал ошибку в нашем коде. Это также может уменьшить количество тестов путем компиляции. - person MikeyB; 25.06.2009
comment
Что было бы хорошим наказанием за нарушение сборки на CI-сервере? А как насчет того, чтобы все мы выполняли TDD, что нам делать, когда у нас появляется красная полоса? : D - person Esko Luontola; 25.06.2009
comment
Потрясающий. Я встречал таких русских программистов. - person hughdbrown; 05.08.2009
comment
Этот парень звучит потрясающе. Но да, я не понимаю, как это должно улучшить размер кода. - person jalf; 07.08.2009
comment
@MikeyB, насчет пригодности я согласен, но в то же время мне просто нравится тестирование компиляцией. Почему мы должны делать то, что машины могут делать лучше? - person harpo; 18.09.2009
comment
Мои глаза! Очки ничего не делают! - person BIBD; 18.09.2009
comment
Конечно, я не могу не думать, что он сохранил бы столько же символов, если бы он просто удалил круглые скобки () вокруг возвращаемых значений; которые, конечно, не нужны в C. :-D - person BIBD; 21.09.2009
comment
Могу вас заверить, этот человек не был типичным русским программистом. Мы НАСТОЯЩИЕ российские программисты склонны наказывать себя упражнениями с гирями и (изредка) сгибанием подковы (хотя это считается скорее делом Архитектора) :)) - person mlvljr; 21.01.2010
comment
@mlvljr: Whimp! Кто угодно может гнуть подкову, нас, ирландских программистов, ПРЯМЫЕ подковы! - person Binary Worrier; 12.02.2010
comment
@Binary Worrier: Это заставляет волноваться :) - person mlvljr; 12.02.2010
comment
HAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHA! Не могу перестать смеяться, читать снова и снова, и это так похоже на моих русских друзей! - person Poni; 30.05.2010
comment
На самом деле, это вы придумали. Да брось! ржу не могу - person Vinicius Kamakura; 20.06.2011
comment
Я, наверное, опоздал, но ...: syntax off отключает подсветку синтаксиса в VIM. - person dsocolobsky; 12.04.2012

Мое худшее:

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

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

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

person Community    schedule 17.03.2009
comment
Сделал это для тестирования! Но, по крайней мере, это было обусловлено чем-то вроде ТЕСТИРОВАНИЕ - person Preet Sangha; 17.03.2009
comment
@ Джошуа: если вы запустите этот код в многопоточной среде, вы просто можете случайно сделать это - person 1800 INFORMATION; 18.03.2009
comment
Если вы чего-то не понимаете, прочтите документацию и узнайте об этом. Не заставляйте его просто так уйти. - АМИНЬ! - person Paul Alexander; 25.06.2009
comment
@ 1800 Информация: я думаю, вы просто потеряете голоса, поэтому не могу дать вам ни одного; p - person wkf; 25.06.2009
comment
Простите меня как программиста, не использующего C ++: основная проблема заключается в том, что потокобезопасная функция конвертируется в небезопасную? Или InterlockedIncrement ожидает указатель, поэтому теперь вы увеличите указатель вместо того, на что он указывает? Или оба? - person Tim Pietzcker; 21.09.2009
comment
Проблема в том, что InterlockedIncrement обычно является атомарной функцией, определенной в Windows API. Поэтому, когда люди вызывают InterlockedIncrement, они ожидают вызова функции, которая гарантированно будет выполняться атомарно. Вместо этого кто-то определил макрос с тем же именем, который оценивает простое, неатомарное приращение. - person jalf; 21.09.2009
comment
Если вы запустите этот код в многопоточной среде, вы просто можете непреднамеренно сделать это. Это неправда: вы можете пропустить только обновление - ›меньше голосов, чем ожидалось ;-) - person usr; 26.09.2009

#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!");
}

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

person Community    schedule 17.03.2009
comment
вы только что написали конвертер java-to-c! ура! - person Andreas Petersson; 17.03.2009
comment
Сообщается как оскорбительное. (Я ребенком!) - person Annika Backstrom; 18.03.2009
comment
Это либо ужасно красиво, либо прекрасно отвратительно. - person Chris Lutz; 01.05.2009
comment
#define System s () сохраняет два символа - person Adam Rosenfield; 25.06.2009
comment
Я не верю, что это было реально, как указал автор вопроса ... но я все равно проголосовал! Извращенность компиляции java в C ++ просто уморительна! - person A. Levy; 30.06.2009
comment
@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. - person Chris Lutz; 09.08.2009
comment
Взгляните на это: mailcom.com/ioccc/chia/chia.c (скачайте и скомпилируйте) - person Roberto Bonvallet; 21.09.2009
comment
@AndreasPetersson Java-to-C ++, если быть точным. - person ; 17.10.2011

#define if while

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

person Community    schedule 17.03.2009
comment
#define while if было бы еще более коварным. - person starblue; 17.03.2009
comment
#define try #define catch (x) #define switch (x) #define if (x) #define while (x) и так далее ... - person 1800 INFORMATION; 18.03.2009
comment
Мы должны уточнить ваше заявление. Затронутые люди не сочли это забавным, . :-) - person Andrew Shepherd; 01.07.2009
comment
Спасибо, я добавил ваше разъяснение - person Michael McCarty; 01.07.2009
comment
Когда я делал домашние задания, я часто делал такие вещи специально, просто чтобы раздражать своих учителей. - person pyon; 01.07.2009
comment
Это хорошая шутка, но она не будет компилироваться, если будут какие-то другие утверждения. Я обнаружил, что #define if (x) if (true) наиболее эффективен. - person Graphics Noob; 07.10.2009
comment
Я всегда предпочитал #define sizeof (x) rand () - person Jon; 16.12.2010

Ужасное:

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

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

person Community    schedule 17.03.2009
comment
Теперь вы задаетесь вопросом, какие языки я могу смоделировать с помощью достаточно умного файла заголовка. - person Bill the Lizard; 17.03.2009
comment
C не красиво. Это довольно некрасиво. - person rlbond; 17.03.2009
comment
Его красота заключается в простоте. Было сказано, что он обладает всей скоростью ассемблера в сочетании с удобочитаемостью ... языка ассемблера :-) Я предпочитаю его раздутому C ++ (хотя я предпочитаю Java в моей повседневной работе из-за его огромной библиотеки). - person paxdiablo; 17.03.2009
comment
Нет, правда. Найдите первоисточник Борна для оболочки Борна. Он сделал именно это, чтобы получить какой-то ублюдочный АЛГОЛ-подобный беспорядок. - person RBerteig; 17.03.2009
comment
На самом деле это довольно часто, насколько я понимаю, это происходит из-за преобразования устаревшего кода из паскаля или чего-то в этом роде. Я видел это в нескольких проектах, я не уверен, почему люди просто не используют замену ... - person SurDin; 17.03.2009
comment
Я плохой человек, если несколько раз подумываю об использовании #define until (x) while (! (X))? (Я никогда этого не делал, пока ты меня не повесил!) - person Bernard; 17.03.2009
comment
@Bernard - Конечно, нет! Как Perlite, я расстраиваюсь, когда вспоминаю, что у меня нет until () или except () в C. Или постфиксную нотацию. Если кто-нибудь может придумать макрос, позволяющий писать i ++ if (i); в C я дам вам пять долларов. И бесплатное объятие. - person Chris Lutz; 19.03.2009
comment
Я видел подобный код раньше. Это была одна из первых вещей, которые я вычистил, как только у меня было время. - person Anthony Giorgio; 15.04.2009
comment
@ Крис-Лутц - i ++ if (i); это i + = (i! = 0); так что вы можете сделать INC_IF_NOT_EQUAL (x, y) {x + = x! = y; } - person LiraNuna; 28.04.2009
comment
#define DO for (int _i = 0; _i ‹= 1; ++ _ i) {if (_i == 1) //// LINE BREAK //// #define IF (cond); если (! (cond)) break; } //// LINE BREAK //// DO printf (a) IF (1 == 2); - person Adrian Panasiuk; 28.08.2009
comment
@paxdiablo: Я слышал, что это называется портативная сборка. Он вполне оправдывает свое название. - person Cristián Romo; 25.11.2009
comment
Ха! Один парень, с которым я беседовал, сделал это. И # определить нет! #define repeat while {#define until (x)} (x) и т. д. Большое спасибо за ваше время ... - person Nick; 28.10.2010
comment
отвратительный? Не всем! Я помню, как видел предложение использовать пару таких #define в печатная книга. Честно говоря, автор упомянул, что это плохая идея, но я видел старые книги where такие определения считаются почти нормальными. - person Sergey Kalinichenko; 22.02.2012

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

#define retrun return

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

person Community    schedule 17.03.2009
comment
Я так часто делаю эту опечатку, что даже подумал. - person Joshua; 17.03.2009
comment
лучше научите своего редактора автоматически заменять возврат на возврат. Я делал такие взломы со своим IRC-клиентом, по крайней мере - person Tetha; 17.03.2009
comment
Эй, думаю, я тоже работал с этим «архитектором». В конце концов он был реклассифицирован как старший архитектор, когда ему нужно было успокоить свое эго. - person BIBD; 18.09.2009
comment
Я переопределил 'rn' на 'rm' в bash, потому что я не мог печатать, а программе чтения новостей 'rn' потребовалось 5 минут для запуска и подключения к серверу. - person Martin Beckett; 12.03.2010
comment
Вы не могли просто открыть новый терминал (или переключиться на другой виртуальный терминал) и сделать killall rn? - person Joe D; 09.08.2010
comment
@Martin Есть sl программа, которая отображает анимацию поезда. (sl означает паровоз.) - person Maxpm; 28.07.2011

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

person Community    schedule 17.03.2009
comment
Ах да, вот почему у меня был специальный заголовок с восстанавливающими здравомыслие # undef после специфичных для MS ... - person Pontus Gagge; 17.03.2009
comment
Решено с помощью (std :: numeric_limits ‹T› :: max) () Но да, довольно неприятно. - person rlbond; 26.06.2009
comment
Добавьте NOMINMAX в свойства вашего проекта в C / C ++ - ›Препроцессор -› Определения препроцессора. - person mattnewport; 07.08.2009
comment
@mattnewport: Спасибо, я даже не мечтал, что есть решение! - person xtofl; 07.08.2009
comment
Это говорит о том, что требуется решение, решение специфическое для min и max. Для каждой другой общей функции, которая имеет затенение макроса, вам нужно другое решение. - person quark; 20.08.2009
comment
Называть функцию или переменную NOMINMAX было бы злом, но это могло произойти. Когда вы сражаетесь с макросами с большим количеством макросов, могут возникнуть непредвиденные жертвы. :) - person bk1e; 19.09.2009
comment
@ bk1e: так случилось, что MS документирует это определение препроцессора, чтобы запретить определение макросов min и max ... Но вы правы. - person xtofl; 20.09.2009
comment
Эти макросы существовали в заголовках MS дольше, чем min, а max были в стандартной библиотеке C ++. - person Richard; 22.09.2009
comment
Еще хуже, когда четыре других ваших внешних зависимости также определяют минимальные / максимальные значения разной степени отстойности, начиная от макросов с плохими скобками и заканчивая хорошо написанными шаблонами, и одна из них просто должна сделать невозможным неопределенность или иначе пропустите их ... В моей книге язык виноват на 50%. - person Roman Starkov; 25.01.2010

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

#define debut {
#define fin }
#define si if(
#define alors ){
#define sinon }else{
#define finsi }
person Community    schedule 17.03.2009
comment
#define zut_alors exit (-1) - person MikeyB; 26.06.2009
comment
Это потрясающе, и это заставило меня громко рассмеяться. Итак, это в основном локализованная французская версия Basic, реализованная на C? - person Bobby; 30.08.2010

У Раймонда Чена есть действительно хорошая напыщенная речь против использования макросов управления потоком . Его лучший пример взят из исходного исходного кода оболочки 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
}
person Community    schedule 17.03.2009
comment
Два момента: во-первых, эта паста испортила исходный отступ. И, во-вторых, код выглядит прекрасно для того, чем он является: Unix C 1970-х годов от ярого поклонника Algol-68. Если _почему счастливчик может выражаться причудливо, то почему Стив Борн не может? Конечно, тот, кто обречен поддерживать его, но не знает Алгола 68, может не оценить эту возможность расширить свои вкусы. - person Darius Bacon; 16.05.2010
comment
Я думаю, что это могло быть задумано Стивом Борном как шутка, а не как предлагаемый стиль программирования. - person Martin Beckett; 29.07.2011
comment
Я видел _1 _..._ 2 _..._ 3 _..._ 4_ и _5 _..._ 6_ раньше (на том самом языке, который Борн изобрел для sh), но _7 _..._ 8_ - настоящая жемчужина. - person hobbs; 20.08.2011

Я хочу представить на конкурс драгоценный камень под названием 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;
}
person Community    schedule 07.08.2009
comment
Вы можете взять код из CVS и посмотреть. Некоторое время назад я разместил более подробную информацию об этом в своем блоге, когда наткнулся на него: bnpcs.blogspot.com/2009/02/ Если бы не проблема с отладкой результирующего кода (проблема наличия очень длинных строк, если они генерируются таким языком), его можно было бы даже использовать в качестве практического генератора кода для C. - person Andrew Y; 19.09.2009
comment
Я могу просто представить, что компиляция занимает вечность - person Paul Fultz II; 23.01.2012

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

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

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

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

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

boost::signals::trackable

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

person Community    schedule 17.03.2009
comment
Я считаю, что ничего не изменилось. - person strager; 17.03.2009
comment
:) Так что это макрос, который зря ломает другие библиотеки. Это даже лучше, чем я ожидал :) - person David Rodríguez - dribeas; 17.03.2009
comment
Qt очень территориален и будет яростно атаковать другие библиотеки, которые пытаются занять его пространство имен :) - person Jeremy Friesner; 07.08.2009
comment
К сожалению, Qt атакует библиотеки за пределами своего пространства имен с использованием макросов. - person David Rodríguez - dribeas; 09.08.2009
comment
К счастью, boost :: signal2 исправил эту проблему;) - person bdonlan; 11.08.2009
comment
Используйте Q_SIGNALS и Q_SLOTS, если вы боитесь этого взаимодействия. - person Tadeusz A. Kadłubowski; 18.09.2009
comment
Поскольку Qt - действительно большой фреймворк, нет особых причин использовать другие библиотеки, особенно boost :: signal. Эти макросы имеют смысл в коде, использующем Qt. Если они вам не нужны, просто отключите их и используйте Q_WHATEVER. Без проблем. - person CMircea; 05.03.2010
comment
Многие программы используют не только «сигналы» повышения, почему они хотя бы не поместили их в пространство имен Qt! - person Martin Beckett; 12.03.2010
comment
Макросы обрабатываются препроцессором до того, как сработает компилятор, они избегают пространств имен. - person David Rodríguez - dribeas; 12.03.2010
comment
@Martin, потому что макросы заменяют строку копипастом; препроцессор не знает, что работает с C ++, для него это просто текст. - person CMircea; 18.05.2010
comment
@iconiK, правда, signal / slots - это выступающие теги, которые MOC может подобрать, они, по крайней мере, могли бы сделать макрос qt :: signal, чтобы было меньше шансов на коллизию. ps вы можете построить QT с флагом, чтобы переименовать их в Q_SIGNAL и Q_SLOT - person Martin Beckett; 18.05.2010
comment
@Martin, на самом деле MOC ищет Q_SIGNAL, Q_SIGNALS, Q_SLOT и Q_EMIT. Заголовочный файл QtGlobal (не уверен, что этот) включает #defines для сигналов, слотов и испускания для вашего удобства; их можно легко отключить с помощью #define, если они мешают, поэтому ваш аргумент не очень хорошо продуман. - person CMircea; 18.05.2010

В 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 для устранения проблем.

person Community    schedule 17.03.2009
comment
Вы можете подавить это, но # определив NOGDI перед включением windows.h, при условии, конечно, что вам не нужно использовать какие-либо различные функции GDI. Есть множество других макросов, таких как WIN32_LEAN_AND_MEAN, NOMINMAX и т. Д., Которые подавляют определение или включение других вещей. - person Adam Rosenfield; 17.03.2009
comment
Хм. Интересный. Но моя точка зрения все еще остается в силе, я должен не забывать #define NOGDI, а также другие макросы, потому что Windows.h злоупотреблял макросами. - person MrValdez; 17.03.2009
comment
GetObject - довольно общее имя функции. Возможно, вы могли бы использовать более информативное имя с учетом контекста, чтобы избежать столкновения. Однако это довольно неприятный случай макроса. - person strager; 17.03.2009
comment
Довольно обидно, что в win32 есть все макросы для преобразования имен API в FooA и FooW. У нас проблема с SendMessage. - person i_am_jorf; 17.03.2009
comment
Проблема в том, что все функции Windows API являются макросами. Меня укусил GetTickCount (). Поскольку большую часть своего программирования я занимаюсь вне Windows, я нашел все определения в заголовках Windows, а затем создал свой собственный включаемый файл, который определил их все, чтобы заранее проверить совместимость. - person jdkoftinoff; 17.03.2009
comment
Я превратил этот пост в вики сообщества. GetObject () - это всего лишь один макрос. Есть еще много всего. Любой может свободно редактировать сообщение. - person MrValdez; 17.03.2009
comment
Какая разница, если ваша функция действительно будет переименована в GetObjectA / GetObjectW? В MFC функция SendMessage фактически заменяется на SendMessageW. - person Mark Ingram; 17.03.2009
comment
@Mark Ingram: проблема в том, что если у вас есть файл заголовка, объявляющий функцию с именем GetObject (), и этот заголовок не включает windows.h, но другой файл включает windows.h перед вашим заголовком, вы получите разные имена и ошибка компилятора или компоновщика. - person Adam Rosenfield; 18.03.2009
comment
Ха-ха, я только что столкнулся с другим вариантом этого в Windows. Вызов метода FillMemory () для класса проверки памяти. Фактическая ошибка: недостаточно фактических параметров для макроса RtlFillmemory. см. msdn.microsoft.com/en-us/library /aa366561(VS.85).aspx - person jdkoftinoff; 31.03.2009
comment
Я думаю, что у нас есть победитель. Это реальный мир, это до смешного плохая идея, и она затронула огромное количество невинных программистов. Тот, кто несет ответственность за эту жемчужину в Microsoft, должен считаться военным преступником ... Самое приятное то, что Microsoft не задумывалась дважды над использованием таких удивительно распространенных имен, как GetObject, SendMessage или CreateWindow. - person jalf; 07.08.2009
comment
Я столкнулся с той же проблемой в классе, у которого была функция-член с именем GetNumberFormat. - person dan04; 20.03.2011

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

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

person Community    schedule 29.10.2009
comment
Только что протестировал этот, по крайней мере, он не компилируется по умолчанию из-за отсутствия включения для random, а затем он закручен красным. Однако, если у вас есть включение случайно, все становится еще хуже - VC ++ 2010 отмечает его как ключевое слово и не показывает всплывающую подсказку с расширением макроса, поэтому IDE не поможет найти это: - / - person OregonGhost; 04.08.2010
comment
Я люблю это! Чистый гений. Представьте, как хорошо вы можете выглядеть, когда отлаживаете это приложение, когда это никому не удалось. - person brice; 22.09.2010

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

Еще хорошие новости об авторе этого ужасного макроса. В августе сотрудник, ответственный за это чудовище, был уволен.

person Community    schedule 25.06.2009
comment
он, очевидно, никогда не слышал: отладка в два раза сложнее, чем написание кода. Следовательно, если вы напишете код настолько умно, насколько это возможно, вы по определению недостаточно умны, чтобы отлаживать его. -Брайан В. Керниган - person Trevor Boyd Smith; 24.06.2011

Я сам сделал следующее и думаю, что кое-что из этого извлек.

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

Интерпретатор Лиспа, конечно, содержал функции car, которые используются в Лиспе для возврата первого элемента в списке, и 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))
person Community    schedule 20.10.2009
comment
I optimized my code by implementing those [..] functions as macros - знаменитые последние слова ... - person BlueRaja - Danny Pflughoeft; 25.05.2010
comment
Я совершал аналогичные нарушения в ранних версиях моего интерпретатора Postscript. Push и pop были функциями, которые были настолько важны, что должны были быть макросами. Но составление выражения, включающего более одного из них, приводит к неопределенному поведению. Неопределенное поведение обнаруживается только при компиляции с -O3. И в -O3 версии функций все равно были бы встроены. - person luser droog; 15.07.2011

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

Его приложение интенсивно использовало препроцессор, чтобы преобразовать язык C в формат, который он мог лучше понять. Но макросы, которые он использовал чаще всего, были определены в заголовочном файле с именем 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) был написан в похожем стиле - marco hell, странные имена, старый английский жаргон и т. Д. К счастью, мы смогли выбросить код, так как я нашел библиотеку OSS, которая выполняла тот же алгоритм десятки раз быстрее.

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

person Community    schedule 23.09.2009
comment
Я довольно очарован притяжениями и архаичным английским, хотя, конечно, я согласен, что код выглядит ужасно. - person Darius Bacon; 16.05.2010

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

Вместо этого у него были наборы файлов, которые были размещены в нескольких папках 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
   }
person Community    schedule 17.03.2009

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

NetworkMessages.h

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

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

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

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

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

person Community    schedule 17.03.2009
comment
И версии могут быть несовместимы друг с другом (нехорошо!). Почему перечисления недостаточно? - person strager; 17.03.2009
comment
И это, и Enum имеют одну и ту же проблему несовместимости. - person MrValdez; 17.03.2009
comment
Теперь я прихожу и сортирую #defines ... и протокол меняется. Или я получаю религию Doxygen и документирую все коды сообщений, и протокол меняется. По крайней мере, перечисление остается стабильным при последнем изменении. - person RBerteig; 17.03.2009
comment
@MrValdez, сохранять порядок в блоке перечислений менее ограничительно, чем сохранять определения в тех же строках относительно начала файла. - person peterchen; 26.06.2009
comment
Я знаю, что это старый пост, но работает ли он вообще? Я имею в виду, что #define просто заменит константы сообщений на LINE, и только тогда LINE будет расширен до номера строки, поэтому каждый раз, когда мы используем одну и ту же константу в разных строках, она будет изменить (на текущий номер строки)? - person XzKto; 20.04.2012

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

#ifdef __cplusplus
#define class _vclass
#endif

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

person Community    schedule 17.03.2009
comment
Вот почему Objective-C использует @class вместо class. - person ; 03.12.2011

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

P

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

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

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

person Community    schedule 19.03.2009

Однажды мне стало скучно, и я играл с блоками в 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)))));

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

person Community    schedule 11.03.2010
comment
Мне однажды наскучили последние слова известного разработчика :) - person Richard J. Ross III; 02.05.2013

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

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

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

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

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

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

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

person Community    schedule 17.03.2009
comment
The code was identical save for the types (so should have used a macro). Нет, ему следовало использовать шаблон. - person BlueRaja - Danny Pflughoeft; 18.02.2011
comment
Ему следовало использовать встроенный strcpy! (и это был код C, а не C ++, поэтому без шаблонов) :-P - person TofuBeer; 18.02.2011
comment
Преждевременная оптимизация - корень всех зол. - person Hubert Kario; 31.12.2011

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

#define FOR  for

и

#define ONE  1
#define TWO  2
...

Кто знал?

person Community    schedule 17.03.2009
comment
Но-но-но БЕЗ ЛИТЕРАЛОВ В КОДЕ! ;) - person Bernard; 17.03.2009
comment
они по-прежнему будут буквальными мон, их следует называть по назначению / намерению, а не по альтернативному символу. Код COBOL, о котором я слышал, они сделали переменную 5 = 5, а позже был код, говорящий, что set 5 = 10 ... люди были очень удивлены, когда они сделали var + 5 и получили var + 10. - person Greg Domjan; 19.03.2009
comment
Никогда не слышал об этом с COBOL, только с FORTRAN. В COBOL, конечно, есть зарезервированные слова ZERO, ZEROS и ZEROES, и все они означают то же самое, что и 0. - person David Thornley; 25.06.2009
comment
Намного лучше, чем #define ONE 0. Если вы хотите посмеяться, поищите это в Интернете и удивитесь ненулевому количеству просмотров. - person reuben; 18.09.2009

#define TRUE 0 // dumbass

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

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

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

person Community    schedule 18.09.2009
comment
Я обвиняю функции библиотеки C в том, что 0 все в порядке: P - person RCIX; 30.11.2010
comment
Почему бы не объявить что-то вроде #define FLAG_SUCCESS 0? - person pyon; 11.01.2011

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

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

void SomeFunction() 
{ 
    SomeLongFunctionName(ParamOne, ParamTwo, ParamThree, ParamFour); CHECK_ERROR  
    //SomeOtherCode  
    Cleanup:    
   //Cleanup code  
}
person Community    schedule 25.06.2009
comment
Хуже того, когда макросы скрывают как операторы goto, так и определения целевых меток. Совершенно магия. - person reuben; 18.09.2009
comment
Я страдал от этого - но макросы выглядели как вызовы функций. - person Jonathan Leffler; 18.09.2009

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

person Community    schedule 03.05.2010

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 {

и т. д. и т. д.

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

person Community    schedule 25.06.2009
comment
Боже мой ... Кажется, у меня кружится голова. - person Michael Foukarakis; 12.08.2010

«Технический менеджер», который раньше был программистом, ввел следующие замечательные макросы в наш проект C ++, потому что считал, что проверка значений NULL в процедурах синтаксического анализа DOM - это слишком много работы:

TRYSEGV
CATCHSEGV

В них использовались setjmp, longjmp и обработчик сигналов для SIGSEGV, чтобы имитировать способность "улавливать" segfault.

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

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

person Community    schedule 18.09.2009
comment
Не уверен, что макросы здесь самая большая проблема, но ничего себе. Это отвратительно. - person reuben; 18.09.2009

В мудрости программирования AI-игр есть глава, в которой используются макросы используется для создания языка сценариев для конечных автоматов.

Так как книга и код являются материалами, защищенными авторским правом, вот ссылка на книгу Google на страницу с подробным описанием макросов (итоговый язык сценария можно найти на странице 324.)

person Community    schedule 17.03.2009
comment
Почему это так плохо? Макросы упрощают код (до некоторой степени). Хорошие языки программирования позволяют создавать мини-языки, отражающие проблемную область. C предлагает препроцессор в качестве основного варианта, если вы не хотите описывать портативный ассемблер ... - person Pontus Gagge; 17.03.2009
comment
Само по себе это не зло. Это злоупотребление препроцессором, чтобы заставить его делать то, для чего он не предназначен. - person MrValdez; 18.03.2009
comment
@MrValdez: Ваше оскорбление - это чей-то гениальный шедевр. :) - person MikeyB; 26.06.2009

В Lucent я однажды взглянул на исходный код исходной оболочки Unix Стива Борна и обнаружил, что он использовал препроцессор C, чтобы C выглядел как Pascal или Algol. Часть, относящаяся к операторам if, выглядела так:

#define IF   if (
#define THEN ) {
#define ELSE } else {
#define ELIF } else if (
#define FI   ; }

Один мой друг сказал мне, что в середине 1990-х он ремонтировал его, и он остался прежним. (Здесь для нас есть урок консервативности, присущей кодовой базе.)

Конечно, вначале Стив делал это в качестве эксперимента, и я уверен, что у него были бы сомнения, если бы он написал это позже.

Обновление: согласно статье Bourne Shell в Википедии, макросы дали ему Algol 68 < / strong> аромат. И полный набор макросов здесь! Очевидно, они повлияли на основателей Международного конкурса запутанного кода C.

person Community    schedule 01.07.2009
comment
Это больше похоже на Algol, чем на Pascal - это Algol, который использует обратные ключевые слова (например, 'fi') для обозначения конца конструкций. Оболочка обычно это использует. Забавный вопрос: почему конец цикла в оболочке Bourne отмечен «done», а не «od»? - person Jonathan Leffler; 07.08.2009
comment
Потому что od означает Octal Dump, который был утилитой в Unix Seventh Edition. - person kmarsh; 07.08.2009
comment
Джонатан, я отметил это в тексте ... Я не помню подробностей, но синтаксис, подобный Алголу, был большой возможностью. Ага, я вижу: od была ранее существовавшей восьмеричной командой дампа. Интересный! - person Jim Ferrans; 07.08.2009
comment
Это один из самых известных ранних примеров использования препроцессора (ab). раньше синтаксис фигурных скобок считался признаком серьезного языка. - person quark; 20.08.2009
comment
это не работает на 'else if', есть ли в algol 'else if'? - person smerlin; 16.01.2010
comment
@smerlin: Щелкните ссылку на полный набор макросов, чтобы увидеть актуальные. Вам нужен макрос ELIF. - person Jim Ferrans; 17.01.2010
comment
Ссылка у меня не сработала, но вот эта: minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh/mac.h - person luser droog; 15.07.2011
comment
Я видел, как некоторые профессора в официально французском колледже раздавали студентам francais.h файл, содержащий такие вещи, как #define si if и #define tant_que while, чтобы заставить их писать код на французском. К счастью, класс никогда не пытался охватить STL. Я бы огрызнулся, если бы студенты написали std::chaine_de_caracteres вместо std::string. - person André Caron; 22.09.2011

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

#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}

Другой - это программа c

c

Для компиляции вам нужно определить c как

-Dc="#include <stdio.h> int main() { char *t =\"Hello World\n\"; while(*t) putc(*t++, stdout); return 0; }"
person Community    schedule 11.08.2011

Сопрограммы (AKA Stackless thread) на C. :) Это злой уловка.

#define crBegin static int state=0; switch(state) { case 0:
#define crReturn(i,x) do { state=i; return x; case i:; } while (0)
#define crFinish }
int function(void) {
    static int i;
    crBegin;
    for (i = 0; i < 10; i++)
        crReturn(1, i);
    crFinish;
}

int decompressor(void) {
    static int c, len;
    crBegin;
    while (1) {
        c = getchar();
        if (c == EOF)
            break;
        if (c == 0xFF) {
            len = getchar();
            c = getchar();
            while (len--)
            crReturn(c);
        } else
        crReturn(c);
    }
    crReturn(EOF);
    crFinish;
}


void parser(int c) {
    crBegin;
    while (1) {
        /* first char already in c */
        if (c == EOF)
            break;
        if (isalpha(c)) {
            do {
                add_to_token(c);
        crReturn( );
            } while (isalpha(c));
            got_token(WORD);
        }
        add_to_token(c);
        got_token(PUNCT);
    crReturn( );
    }
    crFinish;
}
person Community    schedule 23.10.2009

switch (device_id)
{
#ifndef PROD_1
#ifndef PROD_2
#ifdef PROD_3
  case ID_1:
#endif

#ifdef PROD_4

#ifdef PROD_5
  case ID_2:
  case ID_3:
  case ID_4:
#elif defined(PROD_4)
#ifndef PROD_6
  case ID_1:
#endif // PROD_6
  case ID_5:
#endif

  case ID_6:
#endif

#ifdef PROD_7
  #ifndef PROD_8
    case ID_7:
  #endif
#endif

(имена изменены, чтобы защитить невиновных)

Обратите внимание, что мы еще даже не добрались до какого-либо кода, это просто для того, чтобы добраться до первого фактического бита кода. На самом деле это происходит (почти, но не точно таким же образом) для нескольких функций, каждая из которых, в конечном итоге, имеет только 4 возможных варианта (которые также в основном копируют / вставляют с небольшими вариациями и собственными #ifdef).

person Community    schedule 25.06.2009
comment
Это просто прекрасно. А для какой морской свиньи? - person luser droog; 15.07.2011
comment
Если бы я только мог напечатать здесь только улыбку! - person luser droog; 27.07.2011

#define interface struct

в некоторых заголовках Optima ++ (Optima ++ была / была IDE Watcom / Powersoft, с которой мне приходилось работать).

person Community    schedule 07.08.2009
comment
Один из файлов заголовков Windows также # определяет интерфейс к чему-то. - person bk1e; 19.09.2009
comment
+1 Эта ошибка застала меня, и один из моих (гораздо более знающих) коллег отследил ее. - person John; 26.07.2011

#define FLASE FALSE

Программист плохо печатал, и это была его самая частая ошибка.

person Community    schedule 18.09.2009
comment
Я знал, что разработчики используют псевдоним mroe (more) и тому подобное в среде командной строки, но сделать это в коде проще простого. - person Curt Nichols; 18.09.2009
comment
Эй, everoyne nakes miskates! - person Konamiman; 20.10.2009

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

// Here come the register defines:
#define C <something>
#define N <something>
<two more single letter defines>

В нашем коде загрузка файла с жестко заданным именем файла не удалась. Когда мы изменили расположение файла с диска C на диск D, это волшебным образом сработало ...

person Community    schedule 18.09.2010

#define unless(cond) if(!cond)
#define until(cond) while(!cond)

Использовал:

unless( ptr == NULL) 
    ptr->foo();
person Community    schedule 18.09.2009
comment
Даже не безопасно: если (a + b == c) не делает то, что вы думаете! - person Jonathan Leffler; 18.09.2009
comment
Безопаснее, если изменить на: #define if (cond) if (! (Cond)) #define until (cond) while (! (Cond)) - person Joel; 19.09.2009
comment
На самом деле это Perl, так что я могу понять, что автор имеет в виду. На самом деле не злой (не считая комментария Джонатана, который нетрудно исправить), но вполне читаемый (я не могу сказать то же самое для остальной части языка) - person new123456; 24.01.2011

Худшее, что я видел, - это в моем текущем проекте, где есть множество случаев:

#if PROGRAMA
     .
     .
    if(...)
    {
     .
     .
     .
#else
    .
     .
    if(...)
    {
     .
     .
     .
#endif
     }

Да, он закрывает 2 открытия одним закрытием.

person Community    schedule 24.11.2009

Когда я впервые наткнулся на макросы на языке C, они поставили меня в тупик на несколько дней. Ниже то, с чем я столкнулся. Я полагаю, что это имеет смысл для экспертов C и суперэффективно, однако для меня попытка понять, что именно происходит, означало вырезать и вставить все различные макросы вместе, пока не будет доступна вся функция. Неужели это не лучшая практика ?! Что плохого в использовании простой старой функции ?!

#define AST_LIST_MOVE_CURRENT(newhead, field) do { \
typeof ((newhead)->first) __list_cur = __new_prev; \
AST_LIST_REMOVE_CURRENT(field); \
AST_LIST_INSERT_TAIL((newhead), __list_cur, field); \
} while (0) 
person Community    schedule 17.03.2009

С тирадой Раймонда связан следующий ужасный (на мой взгляд, конечно) макрос:

#define CALL_AND_CHECK(func, arg) \
    int result = func(arg);       \
    if(0 != result)               \
    {                             \
        sys.exit(-1);             \
    }                             \

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

Кстати, если бы на момент написания этого макроса использовалась только std :: tr1 :: function, у меня была бы неделя моей жизни назад!

person Community    schedule 17.03.2009
comment
Имейте в виду, что использование CALL_AND_CHECK () дважды в одной области действия приведет к умножению определения result, и даже если этого не произойдет, if (x) CALL_AND_CHECK(foo, y) else CALL_AND_CHECK(foo, z) приведет к неожиданным результатам. - person David Thornley; 24.10.2009

Хорошие макросы: (хотя лично мне не нравятся двойные круглые скобки, необходимые для использования этого синтаксиса; я предпочитаю либо макросы vararg (только C99), либо что-то вроде PRINTF_0, PRINTF_1 и т. Д., В зависимости от количества аргументов)

#ifdef DEBUG
#define PRINTF(x) printf x
#else
#define PRINTF(x)
#endif

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

person Community    schedule 17.03.2009
comment
Исправлено. Избегайте _ с помощью \. - person strager; 17.03.2009
comment
Мне нравится #define D (s) do {s;} while (0), который используется как D (printf (...)); Дополнительные пары имеют смысл ... - person RBerteig; 18.03.2009
comment
вы также можете определить PRINTF как printf, если отладка включена, и как (void), если это не так. Затем он работает с любым количеством аргументов, вы получаете код вроде (void) (1,2,3,4), который ничего не делает. - person Marten; 18.09.2009
comment
@Marten: если это не что-то вроде (void) (LookupDebugId (id), ConvertToString (id)), и в этом случае ConvertToString все равно будет вызываться, только его возвращаемое значение игнорируется, а LookupDebugId может не существовать. Если вы работаете в среде Visual Studio, у вас есть __noop, который делает то, что вы хотите. - person Simon Buchan; 21.09.2009
comment
Также помните, что printf (x) может иметь странные и потенциально катастрофические результаты, если в x есть какие-либо знаки процента. - person David Thornley; 24.10.2009

Что угодно, использующее sendmail и его волшебный синтаксис конфигурации

person Community    schedule 09.08.2009
comment
Да, это очень плохо. Синтаксис m4 не очень хорош. Однажды я покопался в его документации, думая, что могу использовать его для других вещей, и обнаружил, что авторы не включили конструкцию цикла, потому что вы можете создать свою собственную, используя рекурсию. После этого я ни для чего не использовал m4. - person Michael Kohne; 18.09.2009

Я добавляю еще один, который со временем начал меня раздражать:

#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0]))

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

В основном мой аргумент применим к Windows (хотя я предполагаю, что в других SDK ОС есть что-то подобное), где почти каждый, кажется, чувствует необходимость определить этот макрос в заголовке своего проекта, и я не понимаю, почему.

WinNT.h (который входит в состав Windows.h) определяет очень хорошую версию, которая заставляет некоторые шаблоны voodoo вызывать ошибки времени компиляции, если вы передаете тип указателя вместо массива.

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

person Community    schedule 20.08.2009
comment
Я обнаружил, что #define DIM(x) (sizeof x / sizeof * x) избавил меня от необходимости печатать. - person Jamie; 16.10.2009
comment
У меня нет проблем с этой идеей, просто используйте тот, который идет в комплекте с вашим SDK. Если вы хотите сохранить ввод, попробуйте #define DIM (x) ARRAYSIZE (x). - person i_am_jorf; 16.10.2009
comment
Перетаскивание всего ‹windows.h› только для этого макроса кажется несколько излишним. Вы также будете изо всех сил писать непереносимый код. - person Chris Oldwood; 08.06.2010
comment
Если вы пишете код для Windows, вы уже перетаскиваете файл windows.h. Если вы не пишете небольшие консольные приложения и тому подобное. Я имею в виду, вы можете попробовать придерживаться только функций crt, но в конечном итоге вы захотите сделать что-то, для чего вам нужен win32. - person i_am_jorf; 09.06.2010
comment
Я просто не понимаю, почему вы не можете использовать вместо этого функцию. Кроме того, функция будет безопаснее макроса, поскольку она не будет работать с указателями. - person Paul Fultz II; 23.01.2012

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


#define ARGLIST(...) __VA_ARGS__

#define CPPTYPELESSARG(typelessParams) thisptr, typelessParams
#define CPPTYPEDARG(typedParams) void* thisptr, typedParams
#define CPPTYPELESSNOARG thisptr
#define CPPTYPEDNOARG void* thisptr

#define CPPHOOKBODY(hookName, params) void *thisptr; \
    __asm { mov thisptr, ecx } \
    return On##hookName ( params );


#define CHOOKBODY(hookName, typelessParams) return On##hookName( typelessParams );

#define CPPHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, CPPTYPEDARG(typedParams), typelessParams, \
    typedParams, __thiscall, __stdcall, CPPHOOKBODY(hookName, CPPTYPELESSARG(typelessParams)))

#define CPPHOOKNOARG(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, CPPTYPEDNOARG, typelessParams, \
    typedParams, __thiscall, __stdcall, CPPHOOKBODY(hookName, CPPTYPELESSNOARG))

#define CDECLHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, \
    typedParams, __cdecl, __cdecl, CHOOKBODY(hookName, typelessParams))

#define CDECLFUNC(name, address, returnType, args) \
    typedef returnType (__cdecl *name##Ptr)(args); \
    name##Ptr name = (name##Ptr) address;

#define CPPFUNC(name, address, returnType, args) \
    typedef returnType (__thiscall *name##Ptr)(void* thisptr, args); \
    name##Ptr name = (name##Ptr) address;

#define STDFUNC(name, address, returnType, args) \
    typedef returnType (__stdcall *name##Ptr)(args); \
    name##Ptr name = (name##Ptr) address;

#define STDHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, \
    typedParams, __stdcall, __stdcall, CHOOKBODY(hookName, ARGLIST(typelessParams)))

#define HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, hookParams, fnPtrCall, hookCall, hookBody) \
        typedef returnType (fnPtrCall *##hookName##OrigPtr )( typedParams ); \
        class hookName : public IHook \
        { \
        public: \
            typedef hookName##OrigPtr func_type; \
        private: \
            static void* m_origFunction; \
            static bool m_bModifyImport; \
            static std::string m_lib; \
            static std::string m_importFunc; \
            static std::string m_sHookName; \
            static returnType hookCall hookName##FnHook ( hookParams ) \
            { \
                hookBody \
            } \
            static bool ImplIsModifyImport() { return hookName::m_bModifyImport; } \
            static void ImplSetModifyImport(bool bModify) { hookName::m_bModifyImport = bModify; } \
            static const std::string& ImplGetLibName() { return hookName::m_lib; } \
            static const std::string& ImplGetImportFunctionName() { return hookName::m_importFunc; } \
            static void ImplSetOriginalAddress(void* fn) { hookName::m_origFunction = fn; } \
            static void* ImplGetOriginalAddress() { return hookName::m_origFunction; } \
            static returnType On##hookName ( typedParams ); \
            static void* ImplGetNewAddress() { return hookName::##hookName##FnHook; } \
            static const std::string& ImplGetHookName() { return hookName::m_sHookName; } \
        public: \
            hookName() \
            { \
                InjectHookRef.AddHook((IHook*)this); \
                hookName::m_lib = importLib; \
                hookName::m_importFunc = importFunc; \
                hookName::m_sHookName = #hookName; \
                hookName::m_origFunction = NULL; \
                hookName::m_bModifyImport = true; \
            } \
            virtual bool IsModifyImport() const { return hookName::ImplIsModifyImport(); } \
            virtual void SetModifyImport(bool bModify) { hookName::ImplSetModifyImport(bModify); } \
            virtual const std::string& GetHookName() const { return hookName::ImplGetHookName(); } \
            virtual const std::string& GetLibName() const { return hookName::ImplGetLibName(); } \
            virtual const std::string& GetImportFunctionName() const { return hookName::ImplGetImportFunctionName(); } \
            virtual void* GetOriginalAddress() const { return hookName::ImplGetOriginalAddress(); } \
            virtual void* GetNewAddress() const { return hookName::ImplGetNewAddress(); } \
            virtual void SetOriginalAddress(void* fn) { hookName::m_origFunction = fn; } \
            static func_type GetTypedOriginalAddress() { return reinterpret_cast(hookName::m_origFunction); } \
        }; \
        void* hookName::m_origFunction = NULL; \
        bool hookName::m_bModifyImport = false; \
        std::string hookName::m_lib; \
        std::string hookName::m_importFunc; \
        std::string hookName::m_sHookName; \
        static hookName g##hookName##Inst;

Что, в свою очередь, позволило мне сделать это:

CPPHOOK(gIH, "SimEngine.dll", "?AddEntity@Player@@UAEXPAVEntity@@@Z", PlayerAddEntity, void, void* ent, ent);

/* Called when the engine calls Player::AddEntity(entity) */ void PlayerAddEntity::OnPlayerAddEntity(void *thisptr, void *ent) { unsigned int id = getPlayerID(thisptr);

gIH.GetLog()->Info("Player %d adding entity %s.", 
    getPlayerID(thisptr), getEntityName(ent));

gPlayers[id] = thisptr;

/*if( id == 2 && gPlayers[1] && gPlayers[2] )
    EntitySetOwner::GetTypedOriginalAddress() (ent, gPlayers[1]);*/
//gEnts[ent] = Entity(ent, Vector3f());

PlayerAddEntity::GetTypedOriginalAddress() (thisptr, ent);

}

person Community    schedule 07.08.2009

#define "CR_LF" '\r'

Это на какое-то время меня чертовски смутило!

person Community    schedule 23.10.2009

Предыдущий работодатель обнаружил, что BASIC-PLUS в современных системах Unix не реализован, поэтому они попытались реализовать его заново, используя макросы препроцессора C:

#define IF if(
#define THEN ) {
#define ENDIF }
#define GOTO goto L

...и т.д.

Ужасно.

person Community    schedule 01.04.2010
comment
Однажды я работал над кодовой базой, которая была переведена с Паскаля на C, который пытался сохранить синтаксис Паскаля, используя этот подход. - person Chris Oldwood; 08.06.2010

Это взято из популярной программы с открытым исходным кодом. Фактически, это делает некоторые части кода более удобочитаемыми, скрывая уродливое наследие.

#define EP_STATUS    CASTLING][(BOARD_FILES-2)
#define HOLDINGS_SET CASTLING][(BOARD_FILES-1)

Думаю, здесь нет ничего плохого, просто мне это смешно.

http://git.savannah.gnu.org/cgit/xboard.git/tree/common.h

person Community    schedule 06.04.2010

См. этот ответ, чтобы узнать, как коллега-дислексик облегчил жизнь сами с общим файлом заголовка, полным таких вещей, как #define fasle false.

person Community    schedule 06.04.2010

#define PROCESS_AND_RETURN(X) \
X.process(); \
// Important: Return only after invoking virtual method process() \
return X

Из-за «важного» комментария макрос никогда не возвращает объект и CRASH!

person Community    schedule 28.03.2011

Еще один пример «творческого» использования препроцессора, хотя он больше связан с используемой терминологией, чем с механикой (которая невероятно обыденна):

/***********************************************************************
 * OS2 and PCDOS share a lot of common codes.  However, sometimes
 * OS2 needs codes similar to those of UNIX.  NOTPCDOS is used in these
 * situations
 */

#ifdef OS2
#define PCDOS
#define NOTPCDOS
#else /* OS2 */
#ifndef PCDOS
#define NOTPCDOS
#endif /* PCDOS */
#endif /* OS2 */

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

person Community    schedule 17.03.2009

Попробуйте отладить большой проект, который действительно любит макросы, и есть много макросов, которые вызывают другие макросы, которые вызывают другие макросы и т. Д. (5-10 уровней макросов не были редкостью)

А затем добавьте много #ifdef this macrot #else this macro, поэтому, если вы следуете коду, это как дерево разных путей, по которому он может идти.

Единственное решение в большинстве случаев - это предварительно скомпилировать и прочитать это ....

person Community    schedule 17.03.2009

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

ИМХО, это действительно великолепно, так как вы можете получить что-то подобное только с sprintf, который затем требует выделения ресурсов и еще много чего, плюс вся работа полностью выполняется препроцессором.

// Macro: Stringize
//
//      Converts the parameter into a string
//
#define Stringize( L )          #L


// Macro: MakeString
//
//      Converts the contents of a macro into a string
//
#define MakeString( L )     Stringize(L)


// Macro: $LINE
//
//      Gets the line number as a string
//
#define $LINE                   MakeString( __LINE__ )


// Macro: $FILE_POS
//
//      Gets the current file name and current line number in a format the Visual Studio
//      can interpret and output goto
//
// NOTE: For VS to properly interpret this, it must be at the start of the line (can only have whitespace before)
//
#define $FILE_POS               __FILE__ "(" $LINE ") : "

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

#define TEMPLATE_DEFS    typename ReturnType
#define TEMPLATE_DECL   ReturnType
#define FUNCTION_PARAMS void
#define FUNCTION_PASS   
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer0
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1
#define TEMPLATE_DECL   ReturnType, P1
#define FUNCTION_PARAMS P1 param1
#define FUNCTION_PASS   param1
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer1
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1, typename P2
#define TEMPLATE_DECL   ReturnType, P1, P2
#define FUNCTION_PARAMS P1 param1, P2 param2
#define FUNCTION_PASS   param1, param2
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer2
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1, typename P2, typename P3
#define TEMPLATE_DECL   ReturnType, P1, P2, P3
#define FUNCTION_PARAMS P1 param1, P2 param2, P3 param3
#define FUNCTION_PASS   param1, param2, param3
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer3
#include "Callback.inl"

// and so on...

Хотя из-за этого читать «Callback.inl» становится ужасно, это полностью исключает необходимость перезаписи одного и того же кода с другим количеством аргументов. Я также должен упомянуть, что "Callback.inl" #undefs все макросы в конце файла, следовательно, сами макросы не будут мешать другому коду, это просто затрудняет написание "Callback.inl". (хотя чтение и отладка не так уж и сложны)

person Community    schedule 07.08.2009

Наихудшие злоупотребления (и я виноват в том, что иногда это делаю) - это использование препроцессора в качестве некой замены файла данных, то есть:

#define FOO_RELATION \  
BAR_TUPLE( A, B, C) \  
BAR_TUPLE( X, Y, Z) \ 

а потом еще где-нибудь:

#define BAR_TUPLE( p1, p2, p3) if( p1 ) p2 = p3;
FOO_RELATION
#undef BAR_TUPLE

что приведет к:

if( A ) B = C;
if( X ) Y = Z;

Этот шаблон можно использовать для всяких (ужасных) вещей ... генерации операторов switch или огромных блоков if else или взаимодействия с «реальным» кодом. Вы даже можете использовать его для :: cough :: создания контекстного меню в системе контекстного меню, отличной от oo :: cough ::. Не то чтобы я когда-либо делал что-то настолько убогое.

Изменить: исправлены несоответствующие скобки и расширенный пример

person Community    schedule 17.03.2009
comment
GCC фактически использует этот стиль внутри компании. Это полезно в умеренных количествах, но обязательно должно быть хорошо задокументировано. - person Jeff M; 17.03.2009
comment
Неправильная закрытая скобка преднамерена? - person Jonathan Leffler; 07.08.2009

В то время казалось хорошей идеей «передать» макрос в качестве аргумента другому макросу. (Я просто не мог вынести мысли об определении списка значений в нескольких местах.) Код здесь надуманный (и не очень мотивирующий), но дает вам идею:

#define ENUM_COLORS(CallbackMacro) \
    CallbackMacro(RED)   \
    CallbackMacro(GREEN) \
    CallbackMacro(BLUE)  \
    // ...

#define DEFINE_COLOR_TYPE_CALLBACK(Color) \
    Color,

enum MyColorType {
    ENUM_COLORS(DEFINE_COLOR_TYPE_CALLBACK)
};

void RegisterAllKnownColors(void)
{
#define REGISTER_COLOR_CALLBACK(Color) \
    RegisterColor(Color, #Color);

    ENUM_COLORS(REGISTER_COLOR_CALLBACK)
}

void RegisterColor(MyColorType Color, char *ColorName)
{
    // ...
}
person Community    schedule 18.09.2009
comment
Отсутствуют обратные косые черты в последних двух строках #define? - person Jonathan Leffler; 18.09.2009
comment
Ага. Добавлены отсутствующие обратные косые черты. - person reuben; 18.09.2009

В декларациях нашел, к большой путанице:

NON_ZERO_BYTE         Fixed(8)  Constant('79'X),

Позже найдено:

IF WORK_AREA(INDEX) = ZERO_BYTE THEN  /* found zero byte */ 
   WORK_AREA(INDEX) = NON_ZERO_BYTE ; /* reset to nonzero*/
person Community    schedule 17.03.2009

Это не макрос C, но ...

Много лет назад у меня была забавная задача портировать оригинальный Transport Tycoon с ПК на Mac. Версия для ПК была полностью написана на ассемблере, поэтому нам пришлось просмотреть весь исходный код и сначала перенести его на C-код ПК, а затем перенести его на Mac. Большая часть кода была в порядке, даже местами с объектной ориентацией. Однако мировая система рендеринга была невероятной. Для всех, кто не играл в игру, мир может быть просмотрен на одном из трех уровней увеличения. Код для этого был примерно таким:

macro DrawMacro <list of arguments>
   a couple of thousand lines of assembler with loads of conditionals
   based on the macro arguments

DrawZoomLevel1:
   DrawMacro <list of magic numbers>

DrawZoomLevel2:
   DrawMacro <list of more magic numbers>

DrawZoomLevel3:
   DrawMacro <list of even more magic numbers>

Мы, должно быть, использовали немного старую версию MASM, поскольку макрос вызывал сбой ассемблера, когда мы пытались его собрать.

Skizz

person Community    schedule 23.09.2009

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

Вы можете увидеть это здесь: http://www.openbsd.org/cgi-bin/cvsweb/src/sys/nfs/nfsm_subs.h?rev=1.43

person Community    schedule 02.02.2010

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

person Community    schedule 11.03.2010

В коде драйвера для ASIC, который я использовал около 10 лет назад, было много разделов, которые выглядели так:

int foo(state_t *state) {
    int a, b, rval;

    $
    if (state->thing == whatever) {
        $
        do_whatever(state);
    }
    // more code

    $
    return rval;
}

После долгих размышлений мы наконец нашли определение:

#if DEBUG
#define $ dolog("%s %d", __FILE__, __LINE__);
#else
#define $
#endif

Это было трудно найти, потому что ни один из исходных файлов, в которых он использовался, не имел каких-либо включаемых файлов. Был файл с именем top.c исходный файл, который выглядел так:

#include <namechanged.h>
#include <foo.c>
#include <bar.c>
#include <baz.c>

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

person Community    schedule 14.04.2011

#define protected private

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

person Community    schedule 19.03.2009

Любой макрос, использующий оператор конкатенации токенов ##.

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

person Community    schedule 25.06.2009
comment
Я довольно часто использовал ##, но ни один из моих макросов не был особенно сложным - просто создание простой функции получения или установки. - person Michael Kohne; 18.09.2009

Я использовал заголовочные файлы как большие макросы:

// compile-time-caller.h
#define param1 ...
#define param2 ...
#include "killer-header.h"

// killer-header.h
// uses param1 and param2

Я также создал рекурсивные файлы заголовков.

// compile-time-caller.h
#define param1 ...
#define param2 ...
#include "killer-header.h"

// killer-header.h"
#if ... // conditional taking param1 and param2 as parameters
#define temp1 param1
#define temp2 param2
#define param1 ... // expression taking temp1 and temp2 as parameters
#define param2 ... // expression taking temp1 and temp2 as parameters
#include "killer-header.h"
// some actual code
#else
// more actual code
#endif
person Community    schedule 01.07.2009

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

Мне понравилась идея эквивалента макросов зацикливания, но это было слишком.

person Community    schedule 18.09.2009

#undef near
#undef far

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

Оказывается, у Microsoft было несколько #defines для near и far в windows.h, что приводило к ошибкам моих переменных _near и _far в строках, которые их содержали. Было очень сложно отследить проблему, потому что (в то время я был новичком), они существовали только в четырех строках всего проекта, поэтому я не сразу понял.

person Community    schedule 18.09.2009

Нашел в либтидах:

 /* Internal symbols are prefixed to avoid clashes with other libraries */
 #define TYDYAPPEND(str1,str2) str1##str2
 #define TY_(str) TYDYAPPEND(prvTidy,str)

 TY_(DocParseStream)(bar,foo);

Проблема в том, что Visual Studio 2005 и, возможно, другие функции ide go to definition и go to declaration находят только #define TY_(...), а не желаемое объявление DocParseStream.

Может, так безопаснее.

Я думаю, они должны поставить префикс для каждой функции, а не вызывать макрос для выполнения работы ... это загромождает код ... но, возможно, я ошибаюсь в этом. Что вы думаете..?

Ps: Похоже, что почти все внутренние функции const и другие имеют префикс с использованием this .. Мой коллега только что сказал мне, что это обычно .. wtf? Может я что-то упустил.

person Community    schedule 20.10.2009

Будьте осторожны, я написал это как единственный способ обобщать исключения.

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

/// Catch all generic exceptions and log appropriately.
/// Logger is insulated from throwing, so this is a NO THROW operation.
#define CatchAll( msg ) \
    catch( const Poco::Exception &e )   \
    {   \
        try{ LogCritical( Logs.System(), std::string( e.displayText() ).append( msg ) );}catch(...){assert(0);} \
    }   \
    catch( const std::exception &e )    \
    {   \
        try{LogCritical( Logs.System(), std::string( e.what() ).append( msg ) );}catch(...){assert(0);} \
    }   \
    catch(...)  \
    {   \
        try{ LogCritical( Logs.System(), std::string( "Exception caught in " __FUNCTION__ ". " ).append( msg ) );}catch(...){assert(0);}    \
    }   

Мне не нравится сложность, и я ненавижу макросы, но как еще вы могли бы «сделать» общий обработчик catch? Это не должно быть концом, это просто мой общий обработчик catch для изоляции устаревших общедоступных функций и быстрого добавления хотя бы некоторого уровня защиты, когда я знаю, что функция вызывается через граница, которая может возникнуть, если будет выбрано исключение C ++ (добро пожаловать, JNI).

Так заставляет ли это вас бежать и прятаться, или это единственный способ сделать что-то подобное?

В основном...

try{
// some block of code capable of throwing
}
CatchAll()
person Community    schedule 18.05.2011
comment
в java вы бы сделали общий улов, выполнив catch для класса Exception. и это бы все уловило. в вашем коде, я предполагаю, что не все ваши исключения получены из std :: exception? - person Trevor Boyd Smith; 19.05.2011

Все, что использует оператор конкатенации токенов ##. Я видел, как это использовалось для сборки систем псудошаблонов на C ++ и других ужасных вещей. Самое худшее в его использовании - это то, насколько загадочными становятся ваши сообщения об ошибках.

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

Это сработало? Да, это был лучший способ сделать это ... наверное, нет.

person Community    schedule 17.03.2009
comment
Макрос в этом случае для автоматической регистрации класса в синглтоне не так уж и плох, см. Мой первый вопрос о stackoverflow о том, почему: stackoverflow.com/questions/77817/. - person X-Istence; 17.03.2009
comment
Полагаю, вы тоже против assert ()? (подсказка, обычно это макрос, который выглядит точно так же, как то, что вам не нравится) :) - person Tim Post♦; 17.03.2009
comment
Во втором абзаце я сказал, что это хорошее применение оператору. Я до сих пор не считаю это лучшим решением проблемы. - person ; 02.04.2009

person    schedule
comment
Я предпочитаю ‹#define forever для (;;)›, чтобы вы могли писать ‹forever {...}› - person paxdiablo; 17.03.2009
comment
кто-то, кого я ходил в школу с потерянными оценками за ВСЕГДА ... он задохнулся, как это было в учебнике :-) - person TofuBeer; 17.03.2009
comment
Разве предложение Пакса не принадлежит K&R? Тем не менее, я бы сказал, что это того не стоит. - person Jon Ericson; 17.03.2009
comment
На самом деле это совсем не плохо. Я не использую for (;;) идиому, иначе я бы сразу добавил этот макрос в свой код. - person AnT; 25.11.2009
comment
@hayalci: В emacs lisp (и некоторых распространенных реализациях lisp) вы можете (defmacro ever ()), а затем (require 'cl (ever)) - person Joe D; 09.08.2010

person    schedule
comment
Я делал это раньше. Иногда вам просто нужно изменить переменную-член или переопределить функцию в стороннем коде, который вы не можете изменить, а они не предоставили вам аксессор. - person Michael Kristofik; 17.03.2009
comment
Я сделал это вчера и хотел ударить себя за это по голове. Но это делается только в небольшом тестовом приложении, которое использует файлы заголовков из основного приложения. - person Graeme Perrow; 17.03.2009
comment
вау, для модульного тестирования это может быть даже полезно, даже если призраки объектного дизайна будут преследовать вас по ночам. - person Epaga; 17.03.2009
comment
Хммм, неопределенное поведение, легкое нарушение правила одного определения, потенциальные различия в компоновке. Ага, это победитель. - person David Thornley; 25.06.2009
comment
Таким образом, я могу получить доступ к частным и общедоступным материалам, но не к защищенным, и я не могу получить доступ к материалам между ключевым словом class и первым модификатором доступа. - person Ken Bloom; 28.04.2010
comment
@Ken: #define class struct #define protected public - person Yakov Galka; 19.08.2011

person    schedule
comment
И ВЫ хотели написать среду выполнения. Посмотрите, сколько времени я сэкономил! - person Bernard; 17.03.2009
comment
@Trevor: Ага ... умные до сих пор используют Java. бежит в укрытие - person Michael Myers; 17.03.2009
comment
Если вы поместите [] после аргументов вместо перед и #define String int argc, char *, он будет компилироваться (к сожалению). - person Adam Rosenfield; 18.03.2009
comment
Другой мне нравится больше. На этом изображении написано что-то похожее на Java, написанное с помощью нескольких макросов. На другом изображена точная Java, написанная с множеством скрытых макросов и структур с функциональными членами. Первый был дешевой шуткой, а второй - сложной и продуманной шуткой. - person Chris Lutz; 25.06.2009