Qual é o pior abuso de macros / pré-processador do mundo real que você já viu?


176

Qual foi o pior abuso de macros / pré-processador do mundo real que você já se deparou (por favor, não há respostas inventadas da IOCCC * haha ​​*)?

Adicione um pequeno trecho ou história, se for realmente divertido. O objetivo é ensinar algo em vez de sempre dizer às pessoas "nunca use macros".


ps: Eu já usei macros antes ... mas geralmente me livrei delas eventualmente quando tenho uma solução "real" (mesmo que a solução real esteja embutida para que se torne semelhante a uma macro).


Bônus: dê um exemplo em que a macro era realmente melhor do que uma solução que não é macro.

Pergunta relacionada: Quando as macros C ++ são benéficas?


+1 por chamar a atenção para o abuso desenfreado que sofri nas mãos de Macros.
i_am_jorf

37
#define verdadeiro falso // depuração feliz :)
n0rd

O wiki da comunidade significa que ninguém ganhará (ou perderá) reputação com votos positivos / negativos nesta questão ou em suas respostas. Muitas pessoas veem questões como essa como maneiras baratas e fáceis de ganhar reputação; portanto, se você a marcar como wiki da comunidade, é menos provável que as pessoas se desviem e fechem.
Graeme Perrow

2
"as pessoas provavelmente ficarão fora de forma e fechá-la": você está sugerindo que não deseja conteúdo engraçado / engraçado no estouro da pilha?
Trevor Boyd Smith

2
Apenas um ponto rápido, o pré-processador faz parte da linguagem e, portanto, não é ruim / errado de usar, como qualquer outra coisa.
Sr. Garoto

Respostas:


410

De memória, parecia algo assim:

#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)

Sim, está certo, não há chaves de fechamento em nenhuma das funções. O destaque da sintaxe era uma bagunça, então ele usou o vi para editar (não o vim, ele tem uma sintaxe colorida!)

Ele era um programador russo que havia trabalhado principalmente em linguagem assembly. Ele era fanático por economizar o máximo de bytes possível porque já havia trabalhado em sistemas com memória muito limitada. "Era para satélite. Apenas muito poucos bytes, então usamos cada byte para muitas coisas". (mexendo um pouco, reutilizando bytes de instruções da máquina para seus valores numéricos) Quando tentei descobrir que tipos de satélites, só consegui obter "Satélite em órbita. Para fazer órbita".

Ele tinha duas outras peculiaridades: um espelho convexo montado sobre o monitor "Para saber quem está assistindo", e uma saída súbita ocasional da cadeira para fazer dez flexões rápidas. Ele explicou este último como "O compilador encontrou um erro no código. Isso é uma punição".


87
"Compilador encontrou erro no código. Isso é punição". !! A empresa encontrou você ... punição para os colegas de trabalho!
Aprendendo

227
Na Rússia soviética, o programa compila VOCÊ!
Crashworks 17/03/09

53
Quando li sobre o erro do compilador "punição", a primeira coisa que pensei foi "Dobby teve que passar as mãos".
Graeme Perrow

124
Acho que os programadores (inclusive eu) seriam muito mais adequados se todos fizéssemos 10 flexões sempre que um compilador encontrasse um erro em nosso código. Isso também pode reduzir a ocorrência de testes por compilação.
25710 MikeyB

5
Esse cara parece incrível. Mas sim, não vejo como isso deve melhorar o tamanho do código.
jalf

274

Meu pior:

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

Passei dois dias da minha vida rastreando algum problema de contagem de ref COM multi-threaded porque algum idiota colocou isso em um arquivo de cabeçalho. Não vou mencionar a empresa em que trabalhei na época.

A moral desta história? Se você não entender alguma coisa, leia a documentação e aprenda sobre ela. Não basta fazer isso desaparecer.


146
@ Josué: Se você executar esse código em um ambiente multithread, poderá involuntariamente fazer isso
1800

11
"Se você não entender alguma coisa, leia a documentação e aprenda sobre ela. Não faça com que ela desapareça." - AMÉM!
Paul Alexander

2
@ 1800 Informação: Eu acho que você tinha acabado de perder votos, que é por isso que eu não posso lhe dar um; p
WKF

5
Perdoe-me como programador não C ++: O principal problema aqui é que uma função threadsafe é convertida em uma função não threadsafe? Ou que InterlockedIncrement espera um ponteiro, então agora você aumentará o ponteiro em vez do que está apontando? Ou ambos?
Tim Pietzcker 20/09/09

38
O problema é que InterlockedIncrement normalmente é uma função atômica definida na API do Windows. Portanto, quando as pessoas chamam InterlockedIncrement, elas esperam chamar uma função que é garantida para ser executada atomicamente. Em vez disso, alguém definiu uma macro com o mesmo nome, que avalia a uma planície, não atômica incremento
jalf

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

52
Eu prefiro <#define sempre for (;;)> assim você pode escrever <sempre {...}>
paxdiablo

alguém que eu fui para a escola com marcas perderam para a coisa sempre ... ele foi sufocado como era no livro de texto :-)
TofuBeer

6
A sugestão de Pax não é diretamente da K&R? Ainda assim, não vale o esforço, eu diria.
Jon Ericson

Na verdade, isso não é ruim. Não estou usando o for (;;)idioma, caso contrário, adicionaria imediatamente essa macro ao meu código.
AnTev

1
@hayalci: No emacs lisp (e em algumas implementações comuns do lisp), você poderia (defmacro ever ())e então(require 'cl (ever))
Joe D

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

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

Desafio: Alguém pode fazer isso com menos definições e estruturas? ;-)


19
você acabou de escrever um conversor de java para c! horray!
Andreas Petersson

25
Relatado como "ofensivo". (Criança eu!)
Annika Backstrom

40
Isso é horrivelmente bonito ou lindamente horrível.
497 Chris Lutz as

38
@ Marcos - Declara publice static as nothing, void` como int, e main(x)como main(), então public static void main(String[] args)se transforma em int main(). Então se Systemtransforma em S s;s, então se System.out.println("Hello World!");transforma em S s; s.out.println("Hello World!");qual chama a printlnfunção na Festrutura na Sestrutura.
9309 Chris Lutz

2
Dê uma olhada nisso: mailcom.com/ioccc/chia/chia.c (download e compilá-lo)
Roberto Bonvallet

130
#define private public

Eu já fiz isso antes. Às vezes, você só precisa modificar uma variável de membro ou substituir uma função em algum código de terceiros que você não pode alterar - e eles não forneceram um acessador para você.
Michael Kristofik 17/03/2009

30
uau, para testes de unidade, isso pode até ser útil, mesmo que os fantasmas do design de objetos o assuste à noite.
Epaga 17/03/2009

12
Hmmm, comportamento indefinido, violação fácil da regra de uma definição, possíveis diferenças de layout. Sim, este é um vencedor.
David Thornley

10
Portanto, com isso, eu posso acessar itens privados e públicos, mas não itens protegidos, e não consigo acessar os itens entre a classpalavra - chave e o primeiro modificador de acesso.
Ken Bloom

3
@Ken:#define class struct #define protected public
Yakov Galka

107
#define if while

Foi brincadeira de alguém, não foi divertido pelos afetados


22
#define enquanto se seria ainda mais insidioso.
Starblue 17/03/09

7
Deveríamos esclarecer sua declaração. Não foi considerado divertido pelas pessoas afetadas . :-)
Andrew Shepherd

6
Quando eu fazia tarefas de casa, muitas vezes fazia esse tipo de coisa de propósito, apenas para irritar meus professores.
pyon

15
Esta é uma boa brincadeira, mas não será compilada se houver alguma declaração "else". Eu descobri que #define if (x) if (true) é mais eficaz.
Gráficos Noob

32
I #define sizeof (x) rand sempre preferido ()
Jon

106

O hediondo:

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

Sério, se você quiser codificar em Pascal, compre um compilador Pascal, não destrua a bela linguagem C.


45
Agora você está me perguntando quais idiomas posso simular com um arquivo de cabeçalho suficientemente inteligente.
Bill o Lagarto

47
C não é bonito. É bastante feio.
rlbond

27
Sua beleza está em sua simplicidade. Dizem que tem toda a velocidade da linguagem assembly combinada com a legibilidade da ... linguagem assembly :-) Eu prefiro isso do que o C ++ inchado (embora eu prefira Java no meu trabalho diário devido à sua enorme biblioteca).
21420

9
Não mesmo. Encontre a fonte original de Bourne para a casca de bourne. Ele fez exatamente isso para obter algum tipo de bagunça bastarda do tipo ALGOL.
RBerteig

3
#define DO para (int _i = 0; _i <= 1; ++ _ i) {if (_i == 1) //// LINE BREAK //// #define IF (cond); se (! (cond)) quebrar; } //// LINE BREAK //// DO printf ("a") IF (1 == 2);
Adrian Panasiuk

93

Um 'arquiteto', um cara muito humilde, você sabe o tipo, tinha o seguinte:

#define retrun return

porque ele gostava de digitar rápido. O cirurgião cerebral costumava gritar com pessoas mais inteligentes que ele (que eram praticamente todo mundo) e ameaçava usar o cinto preto nelas.


Eu cometi tanto esse erro de digitação que realmente o considerei.
Joshua

4
em vez disso, ensine seu editor a substituir automaticamente o retrun em retorno. Ive feito tais hackeries ao meu cliente de IRC, pelo menos
teta

1
Ei, acho que eu costumava trabalhar com esse 'arquiteto' também. Ele acabou sendo reclassificado arquiteto sênior quando precisou apaziguar seu ego.
BIBD 18/09/09

1
Eu tinha 'rn' redefinido para 'rm' no bash, porque não conseguia digitar e o leitor de notícias 'rn' levou 5 minutos para iniciar e conectar-se ao servidor.
Martin Beckett

2
Você não poderia simplesmente abrir um novo terminal (ou mudar para outro vt) e fazer killall rn?
9138 Joe D

69

Mundo real? O MSVC possui macros em minmax.h, chamadas maxe min, que causam um erro do compilador toda vez que pretendo usar a std::numeric_limits<T>::max()função padrão .


2
Ah, sim, é por isso que eu tinha um cabeçalho especial com a sanidade de restauração # undef de após as específicas-MS ...
Pontus Gagge

3
Resolvido com (std :: numeric_limits <T> :: max) () Mas sim, muito chato.
rlbond

36
Inclua NOMINMAX nas propriedades do seu projeto em C / C ++ -> Pré-processador -> Definições de Pré-processador.
mattnewport

18
Essas macros existem nos cabeçalhos MS por mais de min e max da Biblioteca Padrão C ++.
Richard

4
É ainda pior quando quatro de suas outras dependências externas também definem mín. / Máx. Próprias, de vários graus de suckiness, variando de macros mal parênteses a modelos bem escritos, e uma delas apenas impossibilita sua definição. ou pule de outra forma ... No meu livro, o idioma é responsável por 50%.
Roman Starkov

58

Uma mistura entre sintaxe Pascal e palavras-chave em francês:

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

36
#define zut_alors exit (-1)
MikeyB

4
Isso é incrível e me fez rir alto. Então, essa é basicamente uma versão em francês localizada do Basic implementada em C?
Bobby

56

Raymond Chen tem um discurso muito bom contra o uso de macros de controle de fluxo . Seu melhor exemplo é direto do código-fonte do shell Bourne original:

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

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

2
Dois pontos: um, essa pasta atrapalhou o recuo original. E dois, o código parece bom para o que é: o Unix C dos anos 70, por um fervoroso fã de Algol-68. Se por que o azarado da sorte pode se expressar de um jeito peculiar, por que Steve Bourne não pode? É claro que alguém condenado a mantê-lo que não conhece Algol 68 pode não apreciar essa chance de ampliar seus próprios gostos.
Darius Bacon

Acho que isso pode ser concebido como uma piada por Steve Bourne, em vez de um estilo de programação sugerida
Martin Beckett

2
Eu já vi if... else... elif... fie case... esacantes (na própria linguagem que Bourne inventou para sh), mas loop... poolé uma verdadeira jóia.
Hbbs

54

Gostaria de enviar para o concurso uma gema chamada caos-pp , que implementa uma linguagem funcional por meio das macros do pré-processador.

Um dos exemplos é o cálculo do 500º número de fibonacci inteiramente pelo pré-processador:

O código original antes do pré-processador tem a seguinte aparência:

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

Ao pré-processar o arquivo, obtemos o seguinte resultado (após uma longa espera):

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

1
Você pode pegar o código do CVS e dar uma olhada. Eu tinha colocado mais alguns detalhes sobre isso no meu blog há um tempo atrás, quando me deparei com ele: bnpcs.blogspot.com/2009/02/… Se não fosse pelo problema de depuração do código resultante (o problema de ter linhas muito longas se eles são gerados por um tal "idioma"), poderia ter sido ainda utilizável como um gerador de código prático para C.
Andrew Y

Eu posso apenas imaginar levando uma eternidade para compilar
Paul Fultz II

52

Diretamente do Qt:

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

Muito bom interagir com outras bibliotecas como boost :: signs ... Apenas um exemplo, existem muitas outras no Qt que criam códigos engraçados como:

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

E isso é C ++ ... mas de repente:

boost::signals::trackable

O C ++ não é mais válido.


5
:) Portanto, é uma macro que quebra outras bibliotecas por nada. Isso é ainda melhor do que eu esperava :)
David Rodríguez - dribeas

38
Qt é muito territorial e violentamente atacar outras bibliotecas que tentam ocupar o seu espaço de nomes :)
Jeremy Friesner

21
Infelizmente fora ataques Qt bibliotecas de seu namespace com o uso de macros
David Rodríguez - dribeas

7
Felizmente boost :: signals2 fixou esta questão;)
bdonlan

9
Use Q_SIGNALS e Q_SLOTS se tiver medo dessa interação.
Tadeusz A. Kadłubowski 18/09/09

50

O Windows.h possui muitas funções que abusam das macros.


MrValdez está irritado com a macro GetObject encontrada no Windows.h

A macro GetObject altera a função GetObject () para GetObjectA () ou GetObjectW () (dependendo se a compilação for compilada em não-unicode e unicode, respectivamente)

MrValdez odeia ter que fazer antes da linha de função GetObject

#undef GetObject

Object *GetObject()

A alternativa é alterar o nome da função para algo como GetGameObject ()


jdkoftinoff nos comentários acertou em cheio: O problema é que todas as funções da API do Windows são macros.

Adam Rosenfield mencionou que os problemas podem ser corrigidos definindo NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX, etc. antes de incluir o windows.h para remover os problemas.


3
Você pode suprimir isso, mas # definindo NOGDI antes de incluir o windows.h, desde que você não precise usar nenhuma das várias funções GDI. Existem várias outras macros, como WIN32_LEAN_AND_MEAN, NOMINMAX, etc. que impedem que outras coisas sejam definidas ou incluídas.
23809 Adam Rosenfield

1
GetObject é um nome de função bastante genérico. Talvez você possa ter usado um nome mais descritivo, dado o contexto para evitar a colisão. No entanto, esse é um caso macro bastante ruim.
213

1
É bastante irritante que o win32 tenha todas as macros para converter nomes de API em FooA e FooW. Temos o problema com o SendMessage.
i_am_jorf

6
O problema é que todas as funções da API do Windows são macros. Um que me mordeu foi GetTickCount (). Como faço a maior parte da minha programação fora do Windows, encontrei todas as definições nos cabeçalhos do Windows e, em seguida, criei meu próprio arquivo de inclusão, que as definiu para verificar a compatibilidade com antecedência.
jdkoftinoff

12
Acho que temos um vencedor. É do mundo real, é uma ideia ridiculamente ruim e afetou um grande número de programadores inocentes. Quem é responsável por essa joia na Microsoft deve ser considerado um criminoso de guerra ... A melhor parte é que a Microsoft não pensou duas vezes em usar nomes tão surpreendentemente comuns, como GetObject, SendMessage ou CreateWindow.
jalf

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

isso é tão ruim. É aleatório, o que significa que é acionado em locais diferentes o tempo todo, muda a declaração de retorno, que geralmente possui algum código que pode falhar por si só, altera a palavra-chave de aparência inocente que você nunca suspeitará e usa exceção do espaço padrão, para que você não tente pesquisar nas fontes para encontrar a fonte. Apenas brilhante.


4
Acabei de testar este, pelo menos ele não é compilado por padrão devido a uma inclusão ausente por acaso, e é então rabiscado em vermelho. Se você incluir o item por acidente, no entanto, as coisas pioram - o VC ++ 2010 ainda o marca como uma palavra-chave e não mostra a dica de ferramenta de expansão de macro; portanto, nenhuma ajuda do IDE para encontrar isso: - /
OregonGhost

Eu amo isso! Gênio puro. Imagine o quão bom você pode parecer quando "Debug" Este aplicativo quando ninguém mais conseguiu.
brice

36

Um colega de trabalho e eu encontramos essas duas gemas em alguns dos nossos códigos para streaming de objetos. Essas macros foram instanciadas em cada arquivo de classe que fazia streaming. Não apenas esse código hediondo foi espalhado por toda a nossa base de códigos, quando abordamos o autor original sobre ele, ele escreveu um artigo de 7 páginas em nosso wiki interno, defendendo isso como a única maneira possível de realizar o que ele estava tentando fazer aqui.

Escusado será dizer que, desde então, foi refatorado e não é mais usado em nossa base de código.

Não se deixe impressionar pelas palavras-chave destacadas. Esta é toda uma macro

#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> )

Atualização (17 de dezembro de 2009):

Mais boas notícias sobre esse hediondo autor de macro. Em agosto, o funcionário responsável por essa monstruosidade foi demitido.


3
ele obviamente nunca ouviu falar: "A depuração é duas vezes mais difícil do que escrever o código. Portanto, se você escrever o código da maneira mais inteligente possível, você não é, por definição, inteligente o suficiente para depurá-lo". #Brian W.Kernighan
Trevor Boyd Smith

33

Eu mesmo fiz o seguinte e acho que aprendi algo com isso.

Em 1992, escrevi um pequeno intérprete de Lisp. Não foi implementado no C normal, mas em uma linguagem do tipo C interpretada. Essa linguagem do tipo C usava o pré-processador C padrão.

Obviamente, o intérprete Lisp continha as funções car , que são usadas no Lisp para retornar o primeiro elemento de uma lista e cdr , que retorna o restante da lista. Eles foram implementados assim:

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 */

(Os dados foram armazenados em matrizes, pois não havia estruturas. CONS_OFFSET é a constante 1000.)

car e cdr são usados ​​com freqüência no Lisp e são curtos, e como as chamadas de função não eram muito rápidas na linguagem de implementação, otimizei meu código implementando essas duas funções do Lisp como macros:

#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 verifica se seu argumento é realmente uma lista e, como esse também é usado com frequência no intérprete e é curto, escrevi esse também como uma macro:

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

IS_CONS e LISP_ERROR também foram usados ​​com freqüência, então eu os transformei em macros também:

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

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

Parece razoável?

Mas então, por que todo o sistema travou nesta linha:

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

Eu trabalhei muito tempo para encontrar o problema, até finalmente verificar o que aquela linha curta foi expandida pelo pré-processador. Foi expandido para uma linha de 31370 caracteres, que eu dividi aqui em linhas (502 delas) para maior clareza:

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

18
I optimized my code by implementing those [..] functions as macros- famosas últimas palavras ...
BlueRaja - Danny Pflughoeft

3
Cometi abusos semelhantes nas versões anteriores do meu intérprete Postscript. Push e pop foram as funções que eram tão importantes que deveriam ser macros . Mas compor uma expressão envolvendo mais de um deles leva a um comportamento indefinido. O comportamento indefinido é capturado apenas ao compilar em -O3. E em -O3, as versões das funções teriam sido incorporadas de qualquer maneira.
Luser droog

29

Uma vez tive que portar um aplicativo C do unix para o windows, cuja natureza específica permanecerá sem nome para proteger os culpados. O sujeito que o escreveu era um professor não acostumado a escrever código de produção e claramente chegara ao C de outro idioma. Acontece também que o inglês não era sua primeira língua, embora o país de origem da maioria das pessoas fale muito bem.

Sua aplicação fez uso pesado do pré-processador para transformar a linguagem C em um formato que ele pudesse entender melhor. Mas as macros que ele mais usou foram definidas em um arquivo de cabeçalho chamado 'Thing.h' (sério), que incluía o seguinte:

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

... que ele costumava escrever monstruosidades como as seguintes:

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

Todo o projeto (~ 60.000 LOC) foi escrito em um estilo semelhante - marco inferno, nomes estranhos, jargão olde-inglês etc. Felizmente, conseguimos reproduzir o código desde que encontrei uma biblioteca OSS que executava o mesmo algoritmo dezenas vezes mais rápido.

(Copiei e editei esta resposta que fiz originalmente sobre esta questão ).


3
Estou bastante encantado com os possessivos e o inglês arcaico, por tudo isso, é claro, concordo que o código parece terrível.
Darius Bacon

27

O pior que eu já encontrei foi em um produto que continha um conjunto de executáveis ​​em que o líder técnico designado não havia descoberto as bibliotecas.

Em vez disso, ele tinha conjuntos de arquivos que eram compartilhados em várias pastas do Visual Source Safe. Ele então percebeu que eles precisavam se comportar de maneira um pouco diferente para cada aplicação.

Há várias etapas de refatoração que você pode aplicar aqui.

Em vez disso, ele usou #ifdefs

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

17

O uso do pré-processador LINE para gerar um ID exclusivo para mensagens transmitidas pela rede:

NetworkMessages.h

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

Este é um exemplo em que a macro realmente era melhor do que uma solução não macro:

Em classes de solução não macro, funções e variáveis ​​precisam ser criadas para acompanhar o ID da mensagem. O desenvolvedor pode ou não dificultar o rastreamento do ID da mensagem, o que é mais fácil de ler e depurar.

Além disso, é mais fácil adicionar novas mensagens apenas adicionando a mensagem à fonte.

A desvantagem dessa situação é que o arquivo deve ser incluído em todo o código que usa mensagens. O tempo de compilação aumentaria sempre que uma mensagem fosse editada.


8
E as versões podem ser incompatíveis entre si (nada bom!). Como é que um enum não é suficiente?
213

Isso e o Enum têm exatamente o mesmo problema de incompatibilidade.
21410 MrValdez

17
Agora eu venho e classifico os #defines ... e o protocolo muda. Ou entendo a religião Doxygen e documento todos os códigos de mensagens, e o protocolo muda. Pelo menos um enum é estável sob a última alteração.
RBerteig

3
@MrValdez, é menos restritivo manter um bloco de enumerações em ordem do que manter as definições nas mesmas linhas em relação ao início do arquivo.
Peterchen

Eu sei que este é um post antigo, mas isso funciona? Quero dizer que #define substituirá apenas as constantes da mensagem por LINE e, só então, LINE será expandido para o número da linha; portanto, toda vez que usarmos a mesma constante em linhas diferentes - ela será alterada (para o número da linha atual)?
XzKto

16

Um exemplo bastante ruim:

#ifdef __cplusplus
#define class _vclass
#endif

Isso permite que uma estrutura C que contenha uma variável de membro chamada classseja manipulada por um compilador C ++. Existem dois cabeçalhos com essa construção; um deles também contém '#undef class' no final e o outro não.


1
É por isso que o Objective-C usa em @classvez de class.

14

Em um ano do Concurso Internacional de Codificação C Ofuscada, houve uma entrada em que todo o programa era:

P

Com a condição de que você possa definir Pno makefile como o programa que desejar.

Pelo que me lembro, ele venceu em uma das categorias e, no ano seguinte, surgiu uma regra que não permitia esse estilo de entrada.

(Edit: seis meses depois ou algo assim ... Tenho certeza que a coisa "No IOCCC" não estava na pergunta principal quando escrevi isso ...)


12

Eu estava entediado um dia e estava brincando com blocos no 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)

permitindo coisas "interessantes" como:

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

(algumas definições de função e classe não são mostradas por uma questão de brevidade)


"Eu estava entediado um dia" desenvolvedor famoso últimas palavras :)
Richard J. Ross III

11

O pior que vi foi o não uso :-)

Alguém escreveu uma função strcpy (acho que foi isso ... há mais de 10 anos atrás) dentro de um método (porque não queria a sobrecarga de chamar strcpy ... suspiro).

Eles disseram que isso não funcionaria para caracteres japoneses, então eles adicionaram um "se" no início para executar ASCII ou Unicode. Naquele momento, o código tinha cerca de uma tela ... provavelmente matando a coerência do cache e apagando suas supostas economias para a inclusão do código.

O código era idêntico, exceto para os tipos (portanto, deveria ter usado uma macro).

É claro que o strcpy que eles escreveram foi muito mais lento que o assembler ajustado manualmente que estava na biblioteca padrão ...

É claro que se eles tivessem feito tudo isso como uma macro, poderiam ter sido substituídos por uma chamada para strcpy ...

Claro que abandonei a empresa (não diretamente por causa disso ...)


The code was identical save for the types (so should have used a macro).Não, ele deveria ter usado um modelo.
BlueRaja - Danny Pflughoeft 17/02

1
Ele deveria ter usado o strcpy embutido! (e foi código C não C ++ assim, não modelos) -P
TofuBeer

A otimização prematura é a raiz de todo mal.
Hubert Kario

11

O obrigatório

#define FOR  for

e

#define ONE  1
#define TWO  2
...

Quem sabia?


5
Mas-mas-mas NENHUM LITERAL EM CÓDIGO! ;)
Bernard

eles ainda são literais de segunda a sexta, devem nomeá-los por finalidade / intenção e não por símbolo alternativo. Código COBOL Eu ouvi sobre eles fizeram variável 5 = 5, em seguida, mais tarde teve código dizendo conjunto 5 = 10 ... as pessoas onde verdadeira surpreso quando eles fizeram var + 5 e tem var + 10.
Greg Domjan

1
Nunca ouvi falar disso com COBOL, apenas com FORTRAN. COBOL, é claro, tem ZERO, ZERO, e zeros como palavras reservadas, todos eles significa exatamente a mesma coisa como 0.
David Thornley

Muito melhor que "#define ONE 0". Se você quiser rir, pesquise na web e surpreenda-se com o número diferente de zero de hits.
reuben

11
#define TRUE 0 // dumbass

A pessoa que fez isso se explicou alguns anos depois - a maioria (se não todas) das funções da biblioteca C retornam 0 como uma indicação de que tudo correu bem. Então, ele queria escrever código como:

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

Escusado será dizer que ninguém em nossa equipe (testador ou desenvolvedor) ousou olhar seu código novamente.


1
eu responsabilizo as funções de biblioteca C para fazer 0 "tudo está OK": P
RCIX

6
Por que não declarar algo assim #define FLAG_SUCCESS 0?
pyon 11/01

11

Eu mantenho o código que tem gotos nas macros. Portanto, uma função terá um rótulo no final, mas nenhum goto visível no código da função. Para piorar a situação, a macro está no final de outras instruções geralmente fora da tela, a menos que você role horizontalmente.

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

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

O pior é que as macros ocultam as gotoinstruções e as definições dos rótulos de destino. Totalmente mágico.
reuben

Eu sofri com isso - mas as macros pareciam chamadas de função.
23611 Jonathan Leffler

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

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

3
E você queria escrever um tempo de execução. Veja quanto tempo economizei!
Bernard

4
@ Trevor: Sim ... os inteligentes ainda estão fazendo Java. corre para se esconder
Michael Myers

Se você colocar [] depois de args em vez de antes e "#define String int argc, char *", ele será compilado (infelizmente).
23909 Adam Rosenfield

16
Eu gosto mais do outro. Este mostra algo próximo ao Java sendo escrito com algumas macros. O outro mostra o Java exato sendo escrito com uma infinidade de macros sorrateiras e estruturas com membros da função. A primeira foi uma piada barata, enquanto a segunda foi uma piada elaborada e bem elaborada.
22730 Chris Lutz

10

Por um colega de classe que não entendeu as regras sobre números mágicos:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1


9

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

Você realmente precisa baixá-lo para apreciá-lo. Todo o fluxo de trabalho é determinado por macros. É completamente ilegível. Como um exemplo -

 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 {

etc etc.

E isso é apenas configurar as opções. todo o programa é assim.


2
Oh meu Deus ... acho que estou ficando tonto.
Michael Foukarakis 12/08/10
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.