¿Cuál es el peor abuso de macros / preprocesadores en el mundo real que haya encontrado?


176

¿Cuál es el peor abuso de macros / preprocesadores en el mundo real que haya encontrado (por favor, no hay respuestas artificiales de IOCCC * jaja *)?

Agregue un fragmento breve o una historia si es realmente entretenida. El objetivo es enseñar algo en lugar de siempre decirle a la gente "nunca use macros".


ps: he usado macros antes ... pero generalmente las elimino cuando tengo una solución "real" (incluso si la solución real está en línea, por lo que se vuelve similar a una macro).


Bonificación: dé un ejemplo donde la macro era realmente mejor que una solución no macro.

Pregunta relacionada: ¿ Cuándo son beneficiosas las macros de C ++?


+1 por llamar la atención sobre el abuso desenfrenado que he sufrido a manos de Macros.
i_am_jorf

37
#define verdadero falso // feliz depuración :)
n0rd

Wiki de la comunidad significa que nadie ganará (o perderá) reputación de votos positivos / negativos sobre esta pregunta o sus respuestas. Muchas personas ven preguntas como esta como formas baratas y fáciles de ganar reputación, por lo que si lo marca como wiki comunitario, es menos probable que las personas se doblen y cierren.
Graeme Perrow

2
"es probable que las personas se doblen y cierren": ¿Estás insinuando que no quieres ningún contenido humorístico / divertido en el desbordamiento de pila?
Trevor Boyd Smith el

2
Solo un punto rápido, el preprocesador es parte del lenguaje y, por lo tanto, no es malo / incorrecto de usar, como cualquier otra cosa.
Sr. Boy el

Respuestas:


410

De memoria, se parecía a esto:

#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í, es cierto, no se cierran llaves en ninguna de las funciones. El resaltado de sintaxis fue un desastre, por lo que usó vi para editar (no vim, ¡tiene un color de sintaxis!)

Era un programador ruso que había trabajado principalmente en lenguaje ensamblador. Era fanático de guardar tantos bytes como fuera posible porque anteriormente había trabajado en sistemas con memoria muy limitada. "Era para el satélite. Solo unos pocos bytes, así que usamos cada byte para muchas cosas". (jugueteando, reutilizando bytes de instrucciones de máquina para sus valores numéricos) Cuando intenté averiguar qué tipo de satélites, solo pude obtener "Satélite en órbita. Para hacer que orbite".

Tenía otras dos peculiaridades: un espejo convexo montado encima de su monitor "Por saber quién está mirando", y una salida repentina ocasional de su silla para hacer diez flexiones rápidas. Explicó este último como "El compilador encontró un error en el código. Esto es un castigo".


87
"El compilador encontró un error en el código. Esto es un castigo". !! La compañía te encontró ... castigo a los compañeros de trabajo!
Aprendizaje

227
¡En la Rusia soviética, el programa te compila!
Crashworks

53
Cuando leí sobre el error de compilación "castigo", lo primero que pensé fue "Dobby tuvo que planchar sus manos".
Graeme Perrow

124
Creo que los programadores (incluido yo mismo) serían mucho más adecuados si todos hiciéramos 10 flexiones cada vez que un compilador encontrara un error en nuestro código. Esto también podría reducir la aparición de pruebas por compilación.
MikeyB

55
Ese chico suena genial. Pero sí, no veo cómo se supone que esto mejora el tamaño del código.
jalf

274

Mi peor:

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

Pasé dos días de mi vida rastreando un problema de recuento de referencias COM multiproceso porque un idiota lo puso en un archivo de encabezado. No mencionaré la compañía para la que trabajé en ese momento.

La moraleja de esta historia? Si no comprende algo, lea la documentación y aprenda sobre ello. No solo lo hagas desaparecer.


146
@Joshua: Si ejecuta este código en un entorno multiproceso, podría hacerlo involuntariamente
1800 INFORMACIÓN

11
"Si no comprende algo, lea la documentación y aprenda sobre ello. No solo haga que desaparezca". - AMEN!
Paul Alexander

2
@ 1800 Información: Creo que perderías votos, por eso no puedo darte uno; p
wkf

55
Perdóneme como programador que no es C ++: ¿Es el problema principal aquí que una función segura para subprocesos se convierte en una función no segura para subprocesos? ¿O que InterlockedIncrement espera un puntero, por lo que ahora aumentará el puntero en lugar de lo que está apuntando? ¿O ambos?
Tim Pietzcker

38
El problema es que InterlockedIncrement es normalmente una función atómica definida en la API de Windows. Entonces, cuando las personas llaman a InterlockedIncrement, esperan llamar a una función que se garantiza que se ejecutará atómicamente. En su lugar, alguien define una macro con el mismo nombre, que evalúa a un llano, no atómica de la subasta
JALF

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

52
Prefiero <#define forever para (;;)> para que pueda escribir <forever {...}>
paxdiablo

alguien iba a la escuela con marcas perdidas para la cosa siempre ... se le atragantó como lo fue en el libro de texto :-)
TofuBeer

66
¿No es la sugerencia de Pax directamente de K&R? Aún así, no vale la pena el esfuerzo, diría.
Jon Ericson

Eso en realidad no está nada mal. No estoy usando for (;;)modismos, de lo contrario agregaría de inmediato esta macro a mi código.
ANT

1
@hayalci: En emacs lisp (y algunas implementaciones comunes de lisp) puedes hacerlo (defmacro ever ())y luego(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!");
}

Reto: ¿Alguien puede hacerlo con menos definiciones y estructuras? ;-)


19
¡acabas de escribir un convertidor de java a c! horray!
Andreas Petersson el

25
Reportado como "ofensivo". (¡Bromeo!)
Annika Backstrom

40
Eso es horriblemente hermoso o maravillosamente horrible.
Chris Lutz

38
@Mark - Declara publicy static as nothing, anula` como int, y main(x)como main(), entonces se public static void main(String[] args)convierte en int main(). Luego se Systemconvierte en S s;s, entonces se System.out.println("Hello World!");convierte en S s; s.out.println("Hello World!");que llama a la printlnfunción en la Festructura en la Sestructura
Chris Lutz

2
Eche un vistazo a esto: mailcom.com/ioccc/chia/chia.c (descárguelo y compílelo )
Roberto Bonvallet

130
#define private public

Lo he hecho antes. A veces solo necesita modificar una variable miembro o anular una función en un código de terceros que no puede cambiar, y no le proporcionaron un descriptor de acceso.
Michael Kristofik

30
wow, para las pruebas unitarias, esto incluso podría ser útil, a pesar de que los fantasmas del diseño de objetos te perseguirán por la noche.
Epaga

12
Hmmm, comportamiento indefinido, fácil violación de la regla de una definición, posibles diferencias de diseño. Sí, este es un ganador.
David Thornley

10
Entonces, con eso, puedo acceder a cosas privadas y públicas, pero no a cosas protegidas, y no puedo acceder a las cosas entre la classpalabra clave y el primer modificador de acceso.
Ken Bloom

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

107
#define if while

Era una broma sobre alguien, no fue divertido para los afectados.


22
#definir si sería aún más insidioso.
starblue

77
Deberíamos aclarar su declaración. No fue encontrado divertido por las personas afectadas . :-)
Andrew Shepherd

66
Cuando hacía tareas, a menudo hacía este tipo de cosas a propósito, solo para molestar a mis maestros.
pyon 01 de

15
Esta es una buena broma, pero no se compilará si hay declaraciones "else". Descubrí que #define if (x) if (true) es más efectivo.
Graphics Noob

32
Siempre preferí #define sizeof (x) rand ()
Jon

106

Lo horrible:

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

En serio, si quieres codificar en Pascal, compra un compilador de Pascal, no destruyas el hermoso lenguaje C.


45
Ahora me pregunto qué idiomas puedo simular con un archivo de encabezado lo suficientemente inteligente.
Bill the Lizard

47
C no es hermosa. Es bastante feo.
rlbond

27
Su belleza radica en su simplicidad. Se ha dicho que tiene toda la velocidad del lenguaje ensamblador combinado con la legibilidad de ... lenguaje ensamblador :-) Lo prefiero sobre el C ++ hinchado (aunque prefiero Java en mi trabajo diario debido a su gran biblioteca).
paxdiablo

9
No realmente. Encuentra la fuente original de Bourne para el caparazón de bourne. Hizo exactamente esto para obtener algún tipo de desastre bastardo similar a ALGOL.
RBerteig

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

93

Un 'arquitecto', un tipo muy humilde, ya sabes el tipo, tenía lo siguiente:

#define retrun return

porque le gustaba escribir rápido. Al cirujano cerebral le gustaba gritar a las personas que eran más inteligentes que él (que era casi todo el mundo), y amenazaba con usar su cinturón negro sobre ellos.


Hago tanto error tipográfico que realmente lo consideré.
Joshua

44
más bien, enseñe a su editor a volver a colocar automáticamente en el retorno. He hecho tales hackers a mi cliente de IRC, al menos
Tetha

1
Oye, creo que también solía trabajar con ese 'arquitecto'. Eventualmente fue reclasificado como arquitecto principal cuando necesitaba aplacar su ego.
BIBD

1
Había 'rn' redefinido a 'rm' en bash, porque no podía escribir y el lector de noticias 'rn' tardó 5 minutos en iniciarse y conectarse al servidor.
Martin Beckett

2
¿No podría simplemente abrir una nueva terminal (o cambiar a otra vt) y hacer killall rn?
Joe D

69

¿Mundo real? MSVC tiene macros en minmax.h, llamadas maxy min, que causan un error del compilador cada vez que pretendo usar la std::numeric_limits<T>::max()función estándar .


2
Ah, sí, es por eso que tuve un encabezado especial con # undef que restaura la cordura después de los específicos de la EM ...
Pontus Gagge

3
Resuelto con (std :: numeric_limits <T> :: max) () Pero sí, bastante molesto.
rlbond

36
Agregue NOMINMAX a las propiedades de su proyecto en C / C ++ -> Preprocesador -> Definiciones de preprocesador.
mattnewport

18
Estas macros han existido en los encabezados de MS más de min y max en la Biblioteca estándar de C ++.
Richard

44
Es aún peor cuando cuatro de sus otras dependencias externas también definen mínimas / máximas propias, de diversos grados de succión, que van desde macros mal entre paréntesis hasta plantillas bien escritas, y una de ellas solo tiene que hacer que sea imposible estar indefinido. o de lo contrario, omita estos ... Sin embargo, en mi libro el idioma tiene un 50% de culpa.
Roman Starkov

58

Una mezcla entre la sintaxis de Pascal y las palabras clave en francés:

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

36
#define zut_alors exit (-1)
MikeyB

44
Eso es asombroso y me hizo reír a carcajadas. Entonces, ¿esta es básicamente una versión localizada en francés de Basic implementada en C?
Bobby

56

Raymond Chen tiene una muy buena queja contra el uso de macros de control de flujo . Su mejor ejemplo es directamente del código fuente original del shell Bourne:

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

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

2
Dos puntos: uno, esta pasta estropeó la sangría original. Y dos, el código se ve bien para lo que es: Unix C de los años 70 por un ferviente fanático de Algol-68. Si _por qué el tieso afortunado puede expresarse con un estilo peculiar, ¿por qué Steve Bourne no puede? Por supuesto, alguien condenado a mantenerlo que no conoce Algol 68 puede no apreciar esta oportunidad de ampliar sus propios gustos.
Darius Bacon

Creo que esto podría ser una broma de Steve Bourne en lugar de un estilo de programación sugerido
Martin Beckett

2
He visto if... else... elif... fiy case... esacantes (en el lenguaje que Bourne inventó para sh), pero loop... pooles una verdadera joya.
hobbs

54

Me gustaría presentar para el concurso una gema llamada caos-pp , que implementa un lenguaje funcional por medio de las macros de preprocesador.

Uno de los ejemplos es calcular el número 500 de Fibonacci completamente por el preprocesador:

El código original antes del preprocesador se ve así:

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

preprocesando el archivo obtenemos el siguiente resultado (después de una larga 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
Puede obtener el código de CVS y echar un vistazo. Puse algunos detalles más al respecto en mi blog hace un tiempo cuando me topé con él: bnpcs.blogspot.com/2009/02/… Si no fuera por el problema con la depuración del código resultante (el problema de tener líneas muy largas si son generados por tal "lenguaje"), podría haber sido incluso utilizable como un generador de código práctico para C.
Andrew Y

Me imagino que tomará una eternidad compilar
Paul Fultz II

52

Directamente desde Qt:

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

Realmente agradable interactuar con otras librerías como boost :: señales ... Solo un ejemplo, hay muchas otras en Qt que crean código de aspecto divertido como:

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

Y eso es C ++ ... pero de repente:

boost::signals::trackable

Ya no es válido C ++.


55
:) Por lo tanto, es una macro que rompe otras bibliotecas por nada. Eso es incluso mejor de lo que esperaba :)
David Rodríguez - dribeas

38
Qt es muy territoriales y atacarán brutalmente otras bibliotecas que tratan de ocupar su espacio de nombres :)
Jeremy Friesner

21
Lamentablemente ataques Qt bibliotecas fuera de su espacio de nombres con el uso de macros
David Rodríguez - dribeas

77
Afortunadamente boost :: señales2 ha solucionado este problema;)
bdonlan

9
Use Q_SIGNALS y Q_SLOTS si tiene miedo de esta interacción.
Tadeusz A. Kadłubowski

50

Windows.h tiene muchas funciones que abusaron de las macros.


MrValdez está molesto por la macro GetObject que se encuentra en Windows.

La macro GetObject cambia la función GetObject () en GetObjectA () o GetObjectW () (dependiendo de si la compilación se compila en unicode y unicode, respectivamente)

MrValdez odia tener que hacerlo antes de la línea de función GetObject

#undef GetObject

Object *GetObject()

La alternativa es cambiar el nombre de la función a algo más como GetGameObject ()


jdkoftinoff en los comentarios lo ha clavado: el problema es que todas las funciones API de Windows son macros.

Adam Rosenfield mencionó que los problemas pueden solucionarse definiendo NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX, etc. antes de incluir windows.h para eliminar los problemas.


3
Puede suprimir esto pero # definiendo NOGDI antes de incluir windows.h, siempre que, por supuesto, no necesite usar ninguna de las diversas funciones de GDI. Hay un montón de otras macros como WIN32_LEAN_AND_MEAN, NOMINMAX, etc. que evitan que otras cosas se definan o se incluyan.
Adam Rosenfield

1
GetObject es un nombre de función bastante genérico. Quizás podría haber usado un nombre más descriptivo dado el contexto para evitar la colisión. Sin embargo, ese es un caso macro bastante malvado.
extraño

1
Es bastante molesto que win32 tenga todas las macros para convertir nombres de API a FooA y FooW. Tenemos el problema con SendMessage.
i_am_jorf

66
El problema es que todas las funciones API de Windows son macros. Uno que me mordió fue GetTickCount (). Como hago la mayor parte de mi programación fuera de Windows, encontré todas las definiciones en los encabezados de Windows y luego hice mi propio archivo de inclusión que las definió a todas para verificar la compatibilidad de antemano.
jdkoftinoff

12
Creo que tenemos un ganador. Es del mundo real, es una idea ridículamente mala, y ha afectado a una gran cantidad de programadores inocentes. Quien sea responsable de esta gema en Microsoft debería ser considerado un criminal de guerra ... La mejor parte es que Microsoft no lo pensó dos veces antes de usar nombres tan asombrosamente comunes, como GetObject, SendMessage o CreateWindow.
jalf

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

Esto es tan malo. Es aleatorio, lo que significa que se dispara en diferentes lugares todo el tiempo, cambia la declaración de devolución, que generalmente tiene un código que podría fallar por sí solo, cambia la palabra clave de aspecto inocente que nunca sospechará y utiliza excepción del espacio estándar para que no intente buscar a través de sus fuentes para encontrar su fuente. Sólo brillante.


44
Acabo de probar este, al menos no se compila de manera predeterminada debido a una inclusión faltante para aleatorio, y luego está rojo. Sin embargo, si tiene la inclusión por accidente, las cosas empeoran: VC ++ 2010 lo marca como una palabra clave y no muestra la información sobre herramientas de expansión de macro, por lo que no hay ayuda del IDE para encontrar esto: - /
OregonGhost

¡Me encanta! Genio puro. Imagine lo bien que puede verse cuando "depura" esta aplicación cuando nadie más lo ha logrado.
Brice

36

Un compañero de trabajo y yo encontramos estas dos gemas en algunos de nuestros códigos para la transmisión de objetos. Estas macros se instanciaron en CADA UNO archivo de clase que hizo streaming. Este horrible código no solo se arrojó por toda nuestra base de códigos, cuando nos acercamos al autor original al respecto, escribió un artículo de 7 páginas en nuestro wiki interno defendiendo esto como la única forma posible de lograr lo que estaba tratando de hacer aquí.

No hace falta decir que desde entonces se ha reestructurado y ya no se usa en nuestra base de código.

No se deje intimidar por las palabras clave resaltadas. Esto es TODO 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> )

Actualización (17 de diciembre de 2009):

Más buenas noticias con respecto a este horrible autor macro. A partir de agosto, el empleado responsable de esta monstruosidad fue despedido.


3
obviamente nunca ha oído hablar de: "La depuración es dos veces más difícil que escribir el código en primer lugar. Por lo tanto, si escribe el código de la manera más inteligente posible, por definición, no es lo suficientemente inteligente como para depurarlo". -Brian W. Kernighan
Trevor Boyd Smith

33

Yo mismo hice lo siguiente, y creo que aprendí algo de eso.

En 1992, más o menos, escribí un pequeño intérprete de Lisp. No se implementó en C normal, sino en un lenguaje similar a C interpretado. Sin embargo, este lenguaje tipo C utilizó el preprocesador C estándar.

El intérprete de Lisp, por supuesto, contenía las funciones car , que se usan en Lisp para devolver el primer elemento de una lista, y cdr , que devuelve el resto de la lista. Se implementaron así:

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

(Los datos se almacenaron en matrices, ya que no había estructuras. CONS_OFFSET es la constante 1000).

car y cdr se usan con frecuencia en Lisp, y son cortos, y dado que las llamadas a funciones no eran muy rápidas en el lenguaje de implementación, optimicé mi código implementando esas dos funciones de 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 que su argumento sea en realidad una lista, y dado que ese también se usa con frecuencia en el intérprete, y es breve, también escribí ese como 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 y LISP_ERROR también se usaron con frecuencia, por lo que también los convertí en macros:

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

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

¿Parece razonable?

Pero entonces, ¿por qué se bloqueó todo el sistema en esta línea?

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

Trabajé mucho tiempo para encontrar el problema, hasta que finalmente comprobé a qué se expandió esa línea corta con el preprocesador. Se amplió a una línea de 31370 caracteres, que he dividido aquí en líneas (502 de ellas) para mayor claridad:

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- últimas palabras famosas ...
BlueRaja - Danny Pflughoeft

3
Cometí abusos similares en las primeras versiones de mi intérprete PostScript. Push y pop eran las funciones que eran tan importantes que deberían ser macros . Pero componer una expresión que involucra más de uno de estos conduce a un comportamiento indefinido. El comportamiento indefinido solo se detecta al compilar en -O3. Y en -O3 las versiones de la función habrían sido alineadas de todos modos.
luser droog

29

Una vez tuve que portar una aplicación C de Unix a Windows, cuya naturaleza específica permanecerá sin nombre para proteger al culpable. El tipo que lo escribió era un profesor no acostumbrado a escribir código de producción, y claramente había llegado a C desde algún otro lenguaje. También sucede que el inglés no era su lengua materna, aunque el país del que proviene la mayoría de la gente lo habla bastante bien.

Su aplicación hizo un uso intensivo del preprocesador para torcer el lenguaje C en un formato que pudiera entender mejor. Pero las macros que más usó se definieron en un archivo de encabezado llamado 'Thing.h' (en serio), que incluía lo siguiente:

#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 luego usó para escribir monstruosidades como las siguientes:

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 el proyecto (~ 60,000 LOC) fue escrito en un estilo similar: marco hell, nombres raros, jerga olde-inglés, etc. Afortunadamente pudimos desechar el código ya que encontré una biblioteca OSS que realizaba el mismo algoritmo docenas de veces más rápido

(He copiado y editado esta respuesta que originalmente hice sobre esta pregunta ).


3
Me encantan los posesivos y el inglés arcaico, por todo lo que, por supuesto, estoy de acuerdo, el código parece terrible.
Darius Bacon

27

Lo peor que he encontrado fue en un producto que contiene un conjunto de ejecutables donde el líder técnico designado no había descubierto bibliotecas.

En cambio, tenía conjuntos de archivos que se compartían en varias carpetas de Visual Source Safe. Luego se dio cuenta de que tenían que comportarse de manera ligeramente diferente para cada aplicación.

Hay una serie de pasos de refactorización que puede aplicar aquí.

En cambio, usó #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

El uso del preprocesador LINE para generar una identificación única para los mensajes pasados ​​por la red:

NetworkMessages.h

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

Este es un ejemplo en el que la macro realmente era mejor que una solución no macro:

En una solución no macro, las clases, las funciones y las variables deben construirse para realizar un seguimiento de qué ID es el mensaje. El desarrollador puede o no complicar el seguimiento del ID del mensaje, mientras que esto es más fácil de leer y depurar.

Además, es más fácil agregar nuevos mensajes simplemente agregando el mensaje a la fuente.

La desventaja de esta situación es que el archivo debe incluirse en todo el código que usa mensajes. El tiempo de compilación aumentaría cada vez que se edita un mensaje.


8
Y las versiones pueden ser incompatibles entre sí (¡no es bueno!). ¿Cómo es que una enumeración no fue suficiente?
extraño

Tanto este como el Enum tienen exactamente el mismo problema de incompatibilidad.
MrValdez

17
Ahora vengo y clasifico los #defines ... y el protocolo cambia. O obtengo la religión Doxygen y documento todos los códigos de mensajes, y el protocolo cambia. Al menos una enumeración es estable bajo el último cambio.
RBerteig

3
@MrValdez, es menos restrictivo mantener un bloque de enumeraciones en orden, que mantener las definiciones en las mismas líneas en relación con el inicio del archivo.
Peter

Sé que esta es una publicación antigua, pero ¿funciona? Quiero decir que #define solo reemplazará las constantes de mensaje a LINE y solo entonces LINE se expandirá al número de línea, por lo que cada vez que usemos la misma constante en diferentes líneas, ¿cambiará (al número de línea actual)?
XzKto

16

Un ejemplo bastante malo:

#ifdef __cplusplus
#define class _vclass
#endif

Esto permite una estructura en C que contiene una variable miembro llamada classa ser manejada por un compilador de C ++. Hay dos encabezados con esta construcción en ella; uno de ellos también contiene 'clase #undef' al final y el otro no.


1
Es por eso que Objective-C usa en @classlugar de class.

14

En un año del Concurso Internacional de Codificación de C Ofuscado, hubo una entrada donde todo el programa fue:

P

Con la condición de que pueda definir Pen el archivo MAKE que sea el programa que desee.

Según recuerdo, ganó en una de las categorías, y al año siguiente apareció una regla que prohibía ese estilo de entrada.

(Editar: seis meses después o algo así ... estoy seguro de que "No IOCCC" no estaba en la pregunta principal cuando escribí esto ...)


12

Un día me aburrí y estaba jugando con bloques en 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)

permitiendo cosas "interesantes" 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)))));

(algunas definiciones de funciones y clases no se muestran por razones de brevedad)


Últimas palabras del desarrollador famoso "Me aburrí un día" :)
Richard J. Ross III

11

Lo peor que vi fue la falta de uso :-)

Alguien escribió una función strcpy (creo que eso fue ... hace más de 10 años) dentro de un método (porque no querían la sobrecarga de llamar strcpy ... suspiro).

Se dieron cuenta de que no funcionaría para los caracteres japoneses, por lo que agregaron un "si" al principio para hacer ASCII o Unicode. En ese punto, el código era de una pantalla larga ... probablemente matando la coherencia de caché y borrando sus supuestos ahorros para la incorporación del código.

El código era idéntico, salvo para los tipos (por lo que debería haber utilizado una macro).

Por supuesto, el strcpy que escribieron fue mucho mucho más lento que el ensamblador sintonizado a mano que estaba en la biblioteca estándar ...

Por supuesto, si lo hubieran hecho todo como macro, podría haber sido reemplazado por un llamado a strcpy ...

Por supuesto que dejé la compañía (no directamente por eso ...)


The code was identical save for the types (so should have used a macro).No, debería haber usado una plantilla.
BlueRaja - Danny Pflughoeft

1
¡Debería haber usado el construido en strcpy! (y era código C no C ++, así que no hay plantillas)
:-P

La optimización prematura es la raíz de todo mal.
Hubert Kario

11

Lo obligatorio

#define FOR  for

y

#define ONE  1
#define TWO  2
...

¿Quien sabe?


55
¡Pero, pero, pero NO LITERALES EN EL CÓDIGO! ;)
Bernard

todavía son literales mon, deben nombrarlos por propósito / intención, no como símbolo alternativo. Código COBOL Me enteré de que hicieron la variable 5 = 5 y luego tuvieron el código que decía conjunto 5 = 10 ... la gente estaba realmente sorprendida cuando hicieron var + 5 y obtuvieron var + 10.
Greg Domjan

1
Nunca he oído hablar de eso con COBOL, solo con FORTRAN. COBOL, por supuesto, tiene CERO, ZEROS y CEROES como palabras reservadas, todas ellas significan exactamente lo mismo que 0.
David Thornley

Mucho mejor que "#define ONE 0". Si quieres una risita, busca eso en la web y sorpréndete con el número de visitas que no es cero.
Reuben

11
#define TRUE 0 // dumbass

La persona que hizo esto se explicó algunos años después: la mayoría (si no todas) las funciones de la biblioteca C devuelven 0 como una indicación de que todo salió bien. Entonces, quería poder escribir código como:

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

No hace falta decir que nadie en nuestro equipo (probador o desarrollador) se atrevió a mirar su código nuevamente.


1
culpo a las funciones de la biblioteca C por hacer 0 "todo está bien": P
RCIX

66
¿Por qué no declarar algo así #define FLAG_SUCCESS 0?
pyon

11

Mantengo el código que tiene gotos en macros. Por lo tanto, una función tendrá una etiqueta al final pero no se mostrará ningún goto visible en el código de la función. Para empeorar las cosas, la macro se encuentra al final de otras declaraciones generalmente fuera de la pantalla a menos que se desplace horizontalmente.

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

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

Lo que es peor es cuando las macros ocultan tanto las gotodeclaraciones como las definiciones de las etiquetas de destino. Totalmente mágico
Reuben

He sufrido eso, pero las macros parecían llamadas a funciones.
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
Y USTED quería escribir un tiempo de ejecución. ¡Mira cuánto tiempo ahorré!
Bernard

44
@Trevor: Sí ... los inteligentes todavía están haciendo Java en su lugar. corre a esconderse
Michael Myers

Si coloca [] después de args en lugar de antes, y "#define String int argc, char *", se compilará (lamentablemente).
Adam Rosenfield

16
Me gusta más el otro. Este muestra algo parecido a Java escrito con algunas macros. El otro muestra la escritura exacta de Java con una gran cantidad de macros y estructuras furtivas con miembros de funciones. La primera fue una broma barata, mientras que la segunda fue una broma elaborada y bien pensada.
Chris Lutz

10

Por un compañero de clase que no entendió las reglas sobre los números mágicos:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1


9

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

Realmente tienes que descargarlo para apreciarlo. Todo el flujo de trabajo está determinado por macros. Es completamente ilegible. Como ejemplo -

 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étera etcétera.

Y eso es solo configurar las opciones. todo el programa es así.


2
Dios mío ... creo que me estoy mareando.
Michael Foukarakis
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.