Qual è il peggior abuso di macro / pre-processore del mondo reale che tu abbia mai incontrato?


176

Qual è la peggiore macro / abuso di pre-processore del mondo reale che tu abbia mai incontrato (per favore, nessuna risposta IOCCC inventata * haha ​​*)?

Aggiungi un breve frammento o una storia se è davvero divertente. L'obiettivo è insegnare qualcosa invece di dire sempre alle persone "non usare mai le macro".


ps: ho usato macro prima ... ma di solito mi sbarazzo di loro alla fine quando ho una soluzione "reale" (anche se la soluzione reale è incorporata in modo che diventi simile a una macro).


Bonus: fai un esempio in cui la macro era davvero migliore di una soluzione non macro.

Domanda correlata: quando sono utili le macro C ++?


+1 per aver richiamato l'attenzione sull'abuso dilagante che ho subito per mano dei Macro.
i_am_jorf

37
#define true false // buon debug :)
n0

Community wiki significa che nessuno guadagnerà (o perderà) la reputazione dai voti su / giù su questa domanda o le sue risposte. Molte persone vedono domande come questa come modi economici e facili per guadagnare reputazione, quindi se lo contrassegni come wiki della comunità, è meno probabile che le persone si pieghino completamente e lo chiudano.
Graeme Perrow,

2
"è probabile che le persone si pieghino completamente e lo chiudano": Stai insinuando di non volere alcun contenuto umoristico / divertente in caso di overflow dello stack?
Trevor Boyd Smith,

2
Solo un punto veloce, il pre-processore fa parte del linguaggio e quindi non è male / sbagliato da usare, proprio come qualsiasi altra cosa.
Mr. Boy

Risposte:


410

Dalla memoria, sembrava qualcosa del genere:

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

Sì, è vero, nessuna parentesi graffa di chiusura in nessuna delle funzioni. L'evidenziazione della sintassi era un disastro, quindi ha usato vi per modificare (non vim, ha una colorazione della sintassi!)

Era un programmatore russo che aveva lavorato principalmente in linguaggio assembly. Era fanatico del salvare il maggior numero possibile di byte perché in precedenza aveva lavorato su sistemi con memoria molto limitata. "Era per il satellite. Pochissimi byte, quindi usiamo ogni byte per molte cose." (armeggiando, riutilizzando i byte di istruzioni della macchina per i loro valori numerici) Quando ho cercato di scoprire quali tipi di satelliti, sono riuscito a ottenere solo "Orbiting satellite. Per aver fatto orbitare".

Aveva altre due stranezze: uno specchio convesso montato sopra il suo monitor "Per sapere chi sta guardando", e un'occasionale uscita improvvisa dalla sua sedia per fare dieci rapidi flessioni. Ha spiegato quest'ultimo come "Il compilatore ha riscontrato un errore nel codice. Questa è una punizione".


87
"Errore del compilatore nel codice. Questa è una punizione". !! La compagnia ti ha trovato ... punizione per gli altri impiegati!
Imparare il

227
Nella Russia sovietica, il programma ti compila!
Crashworks,

53
Quando ho letto dell'errore "punizione" del compilatore, la prima cosa a cui ho pensato è stata "Dobby ha dovuto stirare le mani".
Graeme Perrow,

124
Penso che i programmatori (me compreso) sarebbero molto più in forma se tutti facessimo 10 flessioni ogni volta che un compilatore ha riscontrato un errore nel nostro codice. Ciò potrebbe anche ridurre il verificarsi di test per compilazione.
MikeyB,

5
Quel ragazzo sembra fantastico. Ma sì, non vedo come questo dovrebbe migliorare la dimensione del codice.
jalf

274

Il mio peggio:

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

Ho trascorso due giorni della mia vita a rintracciare un problema di conteggio dei riferimenti COM multi-thread perché alcuni idioti lo hanno inserito in un file di intestazione. Non menzionerò la società per cui ho lavorato in quel momento.

la morale di questa storia? Se non capisci qualcosa, leggi la documentazione e scoprila. Non limitarti a farlo andare via.


146
@Joshua: Se esegui questo codice in un ambiente multithread, potresti semplicemente farlo involontariamente
1800 INFORMAZIONI

11
"Se non capisci qualcosa, leggi la documentazione e impara. Non limitarti a farla sparire." - AMEN!
Paul Alexander,

2
@ 1800 Informazioni: penso che potresti perdere i voti, motivo per cui non posso dartene uno; p
wkf

5
Perdonami come programmatore non C ++: il problema principale qui è che una funzione thread-safe viene convertita in una non thread-safe? O che InterlockedIncrement si aspetta un puntatore, quindi ora aumenterai il puntatore invece di quello a cui punta? O entrambi?
Tim Pietzcker,

38
Il problema è che InterlockedIncrement è normalmente una funzione atomica definita nell'API di Windows. Quindi, quando le persone chiamano InterlockedIncrement, si aspettano di chiamare una funzione che è garantita per essere eseguita atomicamente. Invece, qualcuno ha definito una macro con lo stesso nome, che restituisce un semplice incremento non atomico
jalf

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

52
Preferisco <#define forever per (;;)> così puoi scrivere <forever {...}>
paxdiablo

qualcuno a cui andavo a scuola con segni persi per la MAI cosa ... era soffocato come nel libro di testo :-)
TofuBeer

6
Il suggerimento di Pax non è direttamente da K&R? Tuttavia, non vale la pena, direi.
Jon Ericson,

In realtà non è affatto male. Non sto usando il for (;;)linguaggio, altrimenti aggiungerei immediatamente questa macro al mio codice.
Il

1
@hayalci: In emacs lisp (e alcune implementazioni comuni di lisp) potresti (defmacro ever ())e poi(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!");
}

Sfida: qualcuno può farlo con meno definizioni e strutture? ;-)


19
hai appena scritto un convertitore da Java a C! Horray!
Andreas Petersson,

25
Segnalato come "offensivo". (Ragazzino!)
Annika Backstrom,

40
È orribilmente bello o meravigliosamente orribile.
Chris Lutz,

38
@Mark: dichiara publice static as nothing, annulla` come int, e main(x)come main(), così public static void main(String[] args)si trasforma in int main(). Quindi Systemsi trasforma in S s;s, quindi System.out.println("Hello World!");si trasforma in S s; s.out.println("Hello World!");quale chiama la printlnfunzione nella Fstruttura nella Sstruttura.
Chris Lutz,

2
Dai un'occhiata a questo: mailcom.com/ioccc/chia/chia.c (scarica e compila)
Roberto Bonvallet,

130
#define private public

L'ho già fatto prima. A volte è sufficiente modificare una variabile membro o sovrascrivere una funzione in un codice di terze parti che non è possibile modificare e che non ha fornito un programma di accesso per te.
Michael Kristofik,

30
wow per i test unitari questo potrebbe anche essere utile, anche se i fantasmi del design degli oggetti ti perseguiteranno di notte.
Epaga,

12
Hmmm, comportamento indefinito, facile violazione della regola di una definizione, potenziali differenze di layout. Sì, questo è un vincitore.
David Thornley,

10
Quindi, con ciò, posso accedere a cose private e pubbliche, ma non a cose protette, e non posso accedere alle cose tra la classparola chiave e il primo modificatore di accesso.
Ken Bloom,

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

107
#define if while

Era uno scherzo giocato su qualcuno, non è stato trovato divertente da coloro che ne sono stati colpiti


22
#define while if sarebbe ancora più insidioso.
Starblue,

7
Dovremmo chiarire la tua dichiarazione. Non è stato trovato divertente dalle persone colpite . :-)
Andrew Shepherd,

6
Quando facevo compiti a casa, spesso facevo questo tipo di cose apposta, solo per infastidire i miei insegnanti.
pione,

15
Questo è un buon scherzo, ma non verrà compilato se ci sono delle dichiarazioni "altro". Ho scoperto che #define if (x) if (true) è più efficace.
Noob Graphics,

32
Ho sempre preferito #define sizeof (x) rand ()
Jon

106

L'orrendo:

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

Scherzi a parte, se vuoi programmare in Pascal, acquista un compilatore Pascal, non distruggere il bellissimo linguaggio C.


45
Ora mi stai chiedendo quali lingue posso simulare con un file di intestazione abbastanza intelligente.
Bill the Lizard,

47
C non è bellissima. È piuttosto brutto.
rlbond

27
La sua bellezza sta nella sua semplicità. È stato detto che ha tutta la velocità del linguaggio assembly unito alla leggibilità del ... linguaggio assembly :-) Preferisco il C ++ gonfio (anche se preferisco Java nel mio lavoro di giorno a causa della sua enorme libreria).
paxdiablo,

9
No davvero. Trova la fonte originale di Bourne per la shell bourne. Ha fatto esattamente questo per ottenere una specie di pasticcio simile ad ALGOL bastardo.
RBerteig,

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

93

Un "architetto", un ragazzo molto umile, conosci il tipo, aveva il seguente:

#define retrun return

perché gli piaceva scrivere velocemente. Al neurochirurgo piaceva gridare alle persone più intelligenti di lui (che era praticamente tutti) e minacciavano di usare la cintura nera su di loro.


Faccio quel refuso così tanto che l'ho considerato.
Giosuè,

4
piuttosto insegnare al proprio editore a ricollocare nuovamente autore. Almeno ho fatto simili hackerie al mio client IRC
Tetha,

1
Ehi, penso di lavorare anche con quell'architetto. Alla fine fu riclassificato senior architetto quando ebbe bisogno di placare il suo ego.
BIBD,

1
Avevo ridefinito "rn" in "rm" in bash, perché non potevo scrivere e il lettore di news "rn" impiegava 5 minuti per avviarsi e connettersi al server.
Martin Beckett,

2
Non potresti semplicemente aprire un nuovo terminale (o passare a un altro VT) e farlo killall rn?
Joe D,

69

Mondo reale? MSVC ha macro in minmax.h, chiamate maxe min, che causano un errore del compilatore ogni volta che intendo utilizzare la std::numeric_limits<T>::max()funzione standard .


2
Ah, sì, ecco perché ho avuto un'intestazione speciale con # undef che ripristina la sanità mentale dopo quelli specifici per la SM ...
Pontus Gagge

3
Risolto con (std :: numeric_limits <T> :: max) () Ma sì, abbastanza fastidioso.
rlbond

36
Aggiungi NOMINMAX alle proprietà del tuo progetto in C / C ++ -> Preprocessore -> Definizioni preprocessore.
Mattnewport,

18
Queste macro sono esistite nelle intestazioni MS più a lungo di min e max nella libreria standard C ++.
Richard,

4
È ancora peggio quando quattro delle altre dipendenze esterne definiscono anche il loro minimo / massimo, di vari gradi di sugo, che vanno da macro con cattive parentesi a modelli ben scritti, e uno di loro deve solo rendere impossibile essere indefinito o altrimenti salta questi ... Nel mio libro la lingua è del 50% da incolpare.
Roman Starkov,

58

Un mix tra sintassi Pascal e parole chiave francesi:

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

36
#define zut_alors exit (-1)
MikeyB,

4
È fantastico e mi ha fatto ridere ad alta voce. Quindi, questa è fondamentalmente una versione francese localizzata di Basic implementata in C?
Bobby,

56

Raymond Chen ha un'ottima propensione contro l'uso di macro di controllo del flusso . Il suo miglior esempio è direttamente dal codice sorgente della shell Bourne originale:

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
Due punti: uno, questa pasta ha incasinato il rientro originale. E due, il codice sembra perfetto per quello che è: Unix C degli anni Settanta da un fervente fan dell'Algol-68. Se _perché il fortunato avversario può esprimersi in uno stile bizzarro, perché Steve Bourne non può? Certo, qualcuno condannato a mantenerlo che non conosce Algol 68 potrebbe non apprezzare questa possibilità di ampliare i propri gusti.
Darius Bacon,

Penso che questo potrebbe essere inteso come uno scherzo di Steve Bourne piuttosto che uno stile di programmazione suggerito
Martin Beckett,

2
Ho visto if... else... elif... fie case... esacprima (nella stessa lingua inventata da Bourne per sh), ma loop... poolè un vero gioiello.
Hobbs,

54

Vorrei presentare al concorso un gioiello chiamato caos-pp , che implementa un linguaggio funzionale tramite le macro del preprocessore.

Uno degli esempi è il calcolo del 500 ° numero di fibonacci interamente da parte del preprocessore:

Il codice originale prima del preprocessore è il seguente:

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

preelaborando il file otteniamo il seguente risultato (dopo un'attesa piuttosto lunga):

$ 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
Puoi prendere il codice da CVS e dare un'occhiata. Avevo inserito qualche dettaglio in più nel mio blog un po 'di tempo fa, quando mi sono imbattuto in esso: bnpcs.blogspot.com/2009/02/… Se non fosse per il problema con il debug del codice risultante (il problema di avere righe estremamente lunghe se sono generati da un tale "linguaggio"), avrebbe potuto essere addirittura utilizzabile come generatore di codice pratico per C.
Andrew Y,

Posso solo immaginare che ci vorrà un'eternità per la compilazione
Paul Fultz II,

52

Direttamente da Qt:

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

Davvero bello interagire con altre librerie come boost :: signal ... Solo un esempio, ce ne sono molti altri in Qt che creano codice dall'aspetto divertente come:

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

E questo è C ++ ... ma all'improvviso:

boost::signals::trackable

Il C ++ non è più valido.


5
:) Quindi è una macro che rompe le altre librerie per niente. È persino meglio di quanto mi aspettassi :)
David Rodríguez - dribeas,

38
Qt è molto territoriale e attaccherà brutalmente altre biblioteche che tentano di occupare il suo spazio dei nomi :)
Jeremy Friesner,

21
Purtroppo Qt attacca le biblioteche al di fuori del suo spazio dei nomi con l'uso di macro
David Rodríguez - dribeas

7
Fortunatamente boost :: signal2 ha risolto questo problema;)
bdonlan,

9
Usa Q_SIGNALS e Q_SLOTS se hai paura di questa interazione.
Tadeusz A. Kadłubowski,

50

Windows.h ha molte funzioni che hanno abusato delle macro.


MrValdez è infastidito dalla macro GetObject presente in Windows.h

La macro GetObject modifica la funzione GetObject () in GetObjectA () o GetObjectW () (a seconda che la build sia compilata rispettivamente in non unicode e unicode)

MrValdez odia dover fare prima della riga della funzione GetObject

#undef GetObject

Object *GetObject()

L'alternativa è cambiare il nome della funzione in qualcos'altro come GetGameObject ()


jdkoftinoff nei commenti ha risolto il problema: il problema è che tutte le funzioni dell'API di Windows sono macro.

Adam Rosenfield ha affermato che i problemi possono essere risolti definendo NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX, ecc. Prima di includere windows.h per rimuovere i problemi.


3
Puoi sopprimerlo ma # definisci NOGDI prima di includere windows.h, purché ovviamente non sia necessario utilizzare nessuna delle varie funzioni GDI. Ci sono un sacco di altre macro come WIN32_LEAN_AND_MEAN, NOMINMAX, ecc. Che impediscono che altre cose vengano definite o incluse.
Adam Rosenfield,

1
GetObject è un nome di funzione piuttosto generico. Forse avresti potuto usare un nome più descrittivo dato il contesto per evitare la collisione. Tuttavia, questo è un caso macro piuttosto malvagio.
Strager

1
È abbastanza fastidioso che win32 abbia tutte le macro per convertire i nomi API in FooA e FooW. Abbiamo il problema con SendMessage.
i_am_jorf

6
Il problema è che tutte le funzioni dell'API di Windows sono macro. Uno che mi ha morso era GetTickCount (). Dal momento che eseguo la maggior parte della mia programmazione al di fuori di Windows, ho trovato tutte le definizioni nelle intestazioni di Windows e quindi ho creato il mio file include che li ha definiti tutti per verificare in anticipo la compatibilità.
jdkoftinoff,

12
Penso che abbiamo un vincitore. È il mondo reale, è un'idea ridicolmente cattiva e ha interessato un numero enorme di programmatori innocenti. Chiunque sia responsabile di questo gioiello in Microsoft dovrebbe essere considerato un criminale di guerra ... La parte migliore è che Microsoft non ci ha pensato due volte sull'uso di nomi così sorprendentemente comuni, come GetObject, SendMessage o CreateWindow.
jalf

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

questo è proprio così male. È casuale, il che significa che si attiva in luoghi diversi in ogni momento, cambia la dichiarazione di ritorno, che di solito ha un codice su di esso che potrebbe fallire da solo, cambia una parola chiave dall'aspetto innocente su cui non sarai mai sospettoso e usa eccezione dallo spazio standard, quindi non proverai a cercare tra le tue fonti per trovarne la fonte. Semplicemente geniale.


4
Ho appena testato questo, almeno non si compila di default a causa di un'inclusione mancante per casuale, ed è quindi squiggliato in rosso. Se hai l'inclusione per sbaglio, tuttavia, le cose peggiorano - VC ++ 2010 lo contrassegna ancora come parola chiave e non mostra la descrizione dell'espansione macro, quindi nessun aiuto dall'IDE per trovare questo: - /
OregonGhost

Lo adoro! Genio puro. Immagina quanto puoi sembrare bello quando esegui il "Debug" Questa applicazione quando nessun altro è riuscito a farlo.
brice

36

Un collega e ho trovato queste due gemme in alcuni dei nostri codici per lo streaming di oggetti. Queste macro sono state istanziate in OGNI SINGOLO file di classe che ha eseguito lo streaming. Non solo questo codice orribile è stato diffuso in tutta la nostra base di codici, quando ci siamo avvicinati all'autore originale su di esso, ha scritto un articolo di 7 pagine sul nostro wiki interno difendendolo come l'unico modo possibile per realizzare ciò che stava tentando di fare qui.

Inutile dire che da allora è stato modificato e non viene più utilizzato nella nostra base di codice.

Non lasciarti travolgere dalle parole chiave evidenziate. Questa è TUTTA una 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> )

Aggiornamento (17 dicembre 2009):

Altre buone notizie su questo orribile macroautore. A partire da agosto, il dipendente responsabile di questa mostruosità fu licenziato.


3
ovviamente non ha mai sentito parlare di: "Il debugging è due volte più difficile della scrittura del codice in primo luogo. Pertanto, se si scrive il codice nel modo più intelligente possibile, per definizione, non si è abbastanza intelligenti da eseguire il debug." -Brian W. Kernighan
Trevor Boyd Smith,

33

Ho fatto quanto segue da solo e penso di aver imparato qualcosa da esso.

Nel 1992 ho scritto un piccolo interprete Lisp. Non è stato implementato in C normale, ma in un linguaggio interpretato in stile C. Questo linguaggio di tipo C utilizzava tuttavia il pre-processore C standard.

L'interprete Lisp ovviamente conteneva le funzioni car , che viene utilizzato in Lisp per restituire il primo elemento in un elenco, e cdr , che restituisce il resto dell'elenco. Sono stati implementati in questo modo:

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

(I dati sono stati archiviati in array, poiché non c'erano strutture. CONS_OFFSET è la costante 1000.)

car e cdr sono usati frequentemente in Lisp e sono brevi e poiché le chiamate di funzione non erano molto veloci nel linguaggio di implementazione, ho ottimizzato il mio codice implementando quelle due funzioni di Lisp come macro:

#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 che il suo argomento sia in realtà un elenco e dal momento che uno viene anche usato frequentemente nell'interprete ed è breve, ho scritto anche quello come macro:

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

Anche IS_CONS e LISP_ERROR sono stati usati frequentemente, quindi li ho trasformati anche in macro:

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

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

Sembra ragionevole?

Ma poi, perché l'intero sistema si è arrestato in modo anomalo su questa linea:

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

Ho lavorato a lungo per trovare il problema, fino a quando ho finalmente verificato a che cosa era stata estesa quella linea corta dal pre-processore. È stato espanso in una linea di 31370 caratteri, che qui ho diviso in linee (502 di loro) per chiarezza:

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- ultime parole famose ...
BlueRaja - Danny Pflughoeft

3
Ho commesso abusi simili nelle prime versioni del mio interprete Postscript. Push e pop erano le funzioni che erano così importanti che dovrebbero essere macro . Ma comporre un'espressione che coinvolge più di uno di questi porta a comportamenti indefiniti. Il comportamento indefinito viene rilevato solo durante la compilazione in -O3. E a -O3 le versioni delle funzioni sarebbero state comunque incorporate.
Luser droog,

29

Una volta ho dovuto trasferire un'applicazione C da Unix a Windows, la cui natura specifica rimarrà senza nome per proteggere i colpevoli. Il tizio che lo scrisse era un professore non abituato a scrivere codice di produzione, ed era chiaramente arrivato a C da un'altra lingua. Succede anche che l'inglese non fosse la sua prima lingua, anche se il paese in cui proveniva dalla maggior parte delle persone lo parla abbastanza bene.

La sua applicazione fece ampio uso del preprocessore per distorcere il linguaggio C in un formato che potesse comprendere meglio. Ma le macro che usava di più erano definite in un file di intestazione chiamato "Thing.h" (sul serio), che includeva quanto segue:

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

... che poi ha usato per scrivere mostruosità come le seguenti:

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

L'intero progetto (~ 60.000 LOC) è stato scritto in uno stile simile - inferno marco, nomi strani, gergo inglese antico, ecc. Fortunatamente siamo riusciti a buttare il codice da quando ho trovato una libreria OSS che eseguiva lo stesso algoritmo dozzine di volte più veloce.

(Ho copiato e modificato questa risposta che avevo originariamente fatto su questa domanda ).


3
Sono piuttosto affascinato dai possessivi e dall'inglese arcaico, nonostante tutto ciò, naturalmente, sono d'accordo sul fatto che il codice sia terribile.
Darius Bacon,

27

Il peggio che abbia mai incontrato è stato in un prodotto contenente una suite di eseguibili in cui il leader tecnico designato non aveva capito le librerie.

Invece, aveva set di file condivisi in diverse cartelle di Visual Source Safe. Ha quindi capito che dovevano comportarsi in modo leggermente diverso per ogni applicazione.

C'è una serie di passaggi di refactoring che potresti applicare qui.

Invece, ha usato #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

L'uso del preprocessore LINE per generare un ID univoco per i messaggi passati sulla rete:

NetworkMessages.h

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

Questo è un esempio in cui la macro era davvero migliore di una soluzione non macro:

In una soluzione non macro, è necessario creare classi e funzioni per tenere traccia dell'ID del messaggio. Lo sviluppatore può complicare o meno il tracciamento dell'ID del messaggio mentre questo è più facile da leggere ed eseguire il debug.

Inoltre, è più facile aggiungere nuovi messaggi semplicemente aggiungendo il messaggio alla fonte.

Lo svantaggio di questa situazione è che il file deve essere incluso in tutto il codice che utilizza i messaggi. Il tempo di compilazione aumenterebbe ogni volta che un messaggio viene modificato.


8
E le versioni potrebbero essere incompatibili tra loro (non va bene!). Come mai un enum non è bastato?
Strager

Sia questo che l'Enum hanno lo stesso identico problema di incompatibilità.
Mr Valdez,

17
Ora vengo avanti e metto in ordine le #define ... e il protocollo cambia. Oppure ottengo la religione Doxygen e documento tutti i codici dei messaggi e il protocollo cambia. Almeno un enum è stabile sotto quest'ultima modifica.
RBerteig,

3
@MrValdez, è meno restrittivo mantenere un blocco di enum in ordine, piuttosto che mantenere le definizioni sulle stesse righe rispetto all'avvio del file.
Peter

So che questo è un vecchio post, ma funziona anche? Voglio dire #define sostituirà solo le costanti del messaggio in LINE e solo allora LINE verrà espanso al numero di riga, quindi ogni volta che usiamo la stessa costante su righe diverse - cambierà (al numero di riga corrente)?
XzKto

16

Un esempio abbastanza negativo:

#ifdef __cplusplus
#define class _vclass
#endif

Ciò consente a una struttura C che contiene una variabile membro chiamata classdi essere gestita da un compilatore C ++. Ci sono due intestazioni con questo costrutto in esso; uno di questi contiene anche "classe #undef" alla fine e l'altro no.


1
Questo è il motivo per cui Objective-C usa @classinvece di class.

14

In un anno dell'International Obfuscated C Coding Contest, c'era un ingresso in cui l'intero programma era:

P

Con la condizione che tu possa definire Pnel makefile di essere qualunque programma tu voglia.

Ricordo che vinceva in una delle categorie e l'anno successivo era spuntata una regola che impediva quello stile di accesso.

(Modifica: sei mesi dopo o qualcosa del genere ... Sono sicuro che la cosa "No IOCCC" non era nella domanda principale quando ho scritto questo ...)


12

Mi ero annoiato un giorno e stavo giocando con i blocchi in 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)

permettendo cose "interessanti" come:

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

(alcune definizioni di funzioni e classi non mostrate per brevità)


"Sono stato annoiato un giorno" ultime parole del famoso sviluppatore :)
Richard J. Ross III,

11

Il peggiore che ho visto è stato il non uso :-)

Qualcuno ha scritto una funzione strcpy (penso che fosse ... più di 10 anni fa) all'interno di un metodo (perché non volevano il sovraccarico di chiamare strcpy ... sigh).

Hanno capito che non avrebbe funzionato con i caratteri giapponesi, quindi hanno aggiunto un "if" all'inizio per fare ASCII o Unicode. A quel punto il codice era lungo uno schermo ... probabilmente uccideva la coerenza della cache e cancellava i suoi presunti risparmi per l'inserimento del codice.

Il codice era identico salvo per i tipi (quindi avrebbe dovuto usare una macro).

Naturalmente la strcpy che hanno scritto era molto più lenta di quella assemblata a mano che si trovava nella libreria standard ...

Naturalmente se avessero appena fatto tutto come una macro avrebbe potuto essere sostituito con una chiamata a strcpy ...

Certo che ho lasciato la compagnia (non direttamente per questo ...)


The code was identical save for the types (so should have used a macro).No, avrebbe dovuto usare un modello.
BlueRaja - Danny Pflughoeft,

1
Avrebbe dovuto usare lo strcpy integrato! (ed era codice C non C ++ quindi nessun modello) :-P
TofuBeer,

L'ottimizzazione prematura è la radice di tutti i mali.
Hubert Kario,

11

Obbligatorio

#define FOR  for

e

#define ONE  1
#define TWO  2
...

Chi lo sapeva?


5
Ma-ma-ma NESSUN LETTERALE IN CODICE! ;)
Bernard

sono ancora letterali lun, dovrebbero nominarli per scopo / intento, non come simbolo alternativo. Il codice COBOL di cui ho sentito parlare ha reso variabile 5 = 5, poi ha avuto il codice dicendo set 5 = 10 ... le persone sono state davvero sorprese quando hanno fatto var + 5 e hanno ottenuto var + 10.
Greg Domjan

1
Non ne ho mai sentito parlare con COBOL, solo con FORTRAN. COBOL, ovviamente, ha ZERO, ZEROS e ZEROES come parole riservate, tutti significando esattamente la stessa cosa di 0.
David Thornley,

Molto meglio di "#define ONE 0". Se vuoi una risatina, cerca nel Web per quello e lasciati sorprendere dal numero di colpi diverso da zero.
reinviato il

11
#define TRUE 0 // dumbass

La persona che lo ha fatto si è spiegata alcuni anni dopo - la maggior parte (se non tutte) le funzioni della libreria C restituiscono 0 come un'indicazione che tutto è andato bene. Quindi, voleva essere in grado di scrivere codice come:

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

Inutile dire che nessuno nel nostro team (tester o sviluppatore) ha mai osato dare di nuovo un'occhiata al suo codice.


1
incolpo le funzioni della libreria C per aver fatto 0 "tutto è OK": P
RCIX

6
Perché non dichiarare qualcosa del genere #define FLAG_SUCCESS 0?
pyon,

11

Mantengo il codice che ha goto nelle macro. Quindi una funzione avrà un'etichetta alla fine ma nessun goto visibile nel codice funzione. A peggiorare le cose, la macro si trova alla fine di altre istruzioni di solito fuori dallo schermo a meno che non si scorri in senso orizzontale.

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

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

Quel che è peggio è quando le macro nascondono sia le gotoistruzioni che le definizioni delle etichette di destinazione. Totalmente magico.
reinviato il

Ne ho sofferto, ma le macro sembravano chiamate di funzione.
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 tu volevi scrivere un runtime. Guarda quanto tempo ho risparmiato!
Bernard,

4
@Trevor: Sì ... quelli intelligenti stanno ancora facendo Java. corre per la copertura
Michael Myers

Se si inserisce [] after args invece di before e "#define String int argc, char *", verrà compilato (purtroppo).
Adam Rosenfield

16
Mi piace di più l'altro. Questo mostra qualcosa di simile a Java che viene scritto con alcune macro. L'altro mostra che Java esatta è stato scritto con una pletora di macro subdole e strutture con membri di funzione. Il primo era uno scherzo a buon mercato, mentre il secondo era uno scherzo elaborato e ben congegnato.
Chris Lutz,

10

Da un compagno di classe che non ha capito le regole sui numeri magici:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1


9

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

Devi davvero scaricarlo per apprezzarlo. L'intero flusso di lavoro è determinato da macro. È completamente illeggibile. Come esempio -

 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 {

ecc. ecc.

E questo è solo impostare le opzioni. l'intero programma è così.


2
Oh mio Dio ... Penso di avere le vertigini.
Michael Foukarakis,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.