¿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 ++?
c++
c
macros
preprocessor
Trevor Boyd Smith
fuente
fuente
Respuestas:
De memoria, se parecía a esto:
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".
fuente
Mi peor:
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.
fuente
fuente
for (;;)
modismos, de lo contrario agregaría de inmediato esta macro a mi código.(defmacro ever ())
y luego(require 'cl (ever))
Reto: ¿Alguien puede hacerlo con menos definiciones y estructuras? ;-)
fuente
public
ystatic as nothing,
anula` comoint
, ymain(x)
comomain()
, entonces sepublic static void main(String[] args)
convierte enint main()
. Luego seSystem
convierte enS s;s
, entonces seSystem.out.println("Hello World!");
convierte enS s; s.out.println("Hello World!");
que llama a laprintln
función en laF
estructura en laS
estructurafuente
class
palabra clave y el primer modificador de acceso.#define class struct #define protected public
Era una broma sobre alguien, no fue divertido para los afectados.
fuente
Lo horrible:
En serio, si quieres codificar en Pascal, compra un compilador de Pascal, no destruyas el hermoso lenguaje C.
fuente
Un 'arquitecto', un tipo muy humilde, ya sabes el tipo, tenía lo siguiente:
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.
fuente
killall rn
?¿Mundo real? MSVC tiene macros en minmax.h, llamadas
max
ymin
, que causan un error del compilador cada vez que pretendo usar lastd::numeric_limits<T>::max()
función estándar .fuente
Una mezcla entre la sintaxis de Pascal y las palabras clave en francés:
fuente
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:
fuente
if
...else
...elif
...fi
ycase
...esac
antes (en el lenguaje que Bourne inventó para sh), peroloop
...pool
es una verdadera joya.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í:
preprocesando el archivo obtenemos el siguiente resultado (después de una larga espera):
fuente
Directamente desde Qt:
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:
Y eso es C ++ ... pero de repente:
Ya no es válido C ++.
fuente
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
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.
fuente
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.
fuente
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
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.
fuente
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í:
(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:
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:
IS_CONS y LISP_ERROR también se usaron con frecuencia, por lo que también los convertí en macros:
¿Parece razonable?
Pero entonces, ¿por qué se bloqueó todo el sistema en esta línea?
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:
fuente
I optimized my code by implementing those [..] functions as macros
- últimas palabras famosas ...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:
... que luego usó para escribir monstruosidades como las siguientes:
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 ).
fuente
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
fuente
El uso del preprocesador LINE para generar una identificación única para los mensajes pasados por la red:
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.
fuente
Un ejemplo bastante malo:
Esto permite una estructura en C que contiene una variable miembro llamada
class
a 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.fuente
@class
lugar declass
.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
P
en 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 ...)
fuente
Un día me aburrí y estaba jugando con bloques en Objective-C ...
permitiendo cosas "interesantes" como:
(algunas definiciones de funciones y clases no se muestran por razones de brevedad)
fuente
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 ...)
fuente
The code was identical save for the types (so should have used a macro).
No, debería haber usado una plantilla.Lo obligatorio
y
¿Quien sabe?
fuente
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:
No hace falta decir que nadie en nuestro equipo (probador o desarrollador) se atrevió a mirar su código nuevamente.
fuente
#define FLAG_SUCCESS 0
?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.
fuente
goto
declaraciones como las definiciones de las etiquetas de destino. Totalmente mágicofuente
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
fuente
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 -
etcétera etcétera.
Y eso es solo configurar las opciones. todo el programa es así.
fuente