Está en la página 1de 53

Suscríbete a DeepL Pro para poder tradu

Más información disponible en www.De

3
Leer y escribir código

Hasta ahora he hablado de la dificultad de entender el código y el


software, y de la importancia de vincular la materialidad del código
con sus prácticas sociales para ayudarnos a entenderlo. Uno de los
mayores problemas a la hora de entender el código es encontrar los
ejemplos adecuados para ilustrar este debate, por lo que a continuación
presentaré algunos ejemplos de código que lo harán más visible y
mostrarán por qué es útil leerlo. En Internet hay innumerables
fragmentos de código y repositorios con ejemplos de código que
muestran desde el "¡Hola, mundo!", tradicionalmente el primer
ejemplo de programación que se enseña en informática, hasta
complejos sistemas de gestión de bases de datos o incluso sistemas
operativos completos, como Gnu/Linux. Aunque quiero subrayar la
importancia de conectar los puntos asociados al código y al software,
también quiero evitar una tediosa lección de programación en lo que
pronto puede convertirse en un tema de debate bastante árido. Por
este motivo, he intentado elegir ejemplos que demuestren claramente
lo que quiero decir o que sean interesantes por sí mismos. En
segundo lugar, he intentado dejar claro que, cuando se habla de
código, hay que ser consciente de que los fragmentos de código
pueden ser difíciles de entender cuando se sacan de contexto y a
menudo es necesaria la documentación que los acompaña para
entenderlos. Por ejemplo, el estudio teórico de los métodos
computacionales a menudo se centra únicamente en la lógica de
programación en sí, sin prestar atención a la información interesante
que puede encontrarse en las secciones de comentarios,
documentación, nombres de variables, nombres de funciones, etc.
En este capítulo examinaremos más detenidamente la distinción entre
"código" y "software". Seguiré utilizando "código" (como código
delegado) para referirme a las prácticas textuales y sociales de escritura,
comprobación y distribución del código fuente. En cambio, "software"
(como código
64
Lectura y escritura de
c ó d i g o s 65
código) se referirá al código objeto, es decir, al código que se ha
compilado en un formato ejecutable, que incluye productos finales de
software, como sistemas operativos, aplicaciones o productos fijos de
código como Photoshop, Word y Excel. Al hablar del código y el
software, también nos ocuparemos de las prácticas culturales que rodean
su uso. Esto nos permite reflexionar sobre los procesos de creación de
software a través de la programación informática, y también sobre el tema
relacionado de la piratería informática como el uso inteligente y a veces
inspirado de la programación para cambiar la ejecución normal del
código o de subvertir sus funciones previstas (código prescrito).
En este sentido, no me centraré en el nivel de la pantalla, el llamado
esencialismo de la pantalla, sino que el análisis se centrará en cómo se
construye el código por su relación con un conjunto maquínico en
funcionamiento. Tampoco haré lecturas literarias de la forma textual del
código, ya que es crucial que tengamos plenamente en cuenta la doble
articulación del código, como simbólico y material. La forma en que se
crea el código, y se prueba, mantiene y ejecuta, forma parte de nuestra
atención a la materialidad y obcecación del código. Así pues,
haciéndonos eco de lo expuesto en el último capítulo, permaneceremos
atentos al código en su multiplicidad, es decir, como literatura,
mecanismo, forma espacial (organización) y depósito de normas,
valores, pautas y procesos sociales.

Pruebas de resistencia

Para localizar la materialidad del código, desarrollo la noción de Latour


(1988) de "prueba de fuerza" introducida en Irreductions. En este caso,
una prueba puede considerarse legítima siempre que las fuerzas se
midan de acuerdo con los principios de un conjunto de reglas. En
oposición al giro lingüístico, la noción de prueba se inclina hacia el
realismo. En efecto, para que las personas puedan llegar a un acuerdo
sobre un programa informático en la práctica, y no sólo en principio,
tiene que producirse una prueba de realidad, acompañada de una
codificación o, al menos, de una formulación explícita de una prueba
válida. Por tanto, cada reivindicación lleva asociada una serie de
pruebas a las que se puede recurrir para respaldar sus afirmaciones. Un
requisito primordial es la obligación de especificar el tipo de resistencia
que interviene en una prueba concreta y de disponer un dispositivo de
prueba. No superar las pruebas indica que no se ha demostrado el
"hecho concreto" del software y, por consiguiente, que el software en sí
sigue siendo vapourware, es decir, irreal o inmaterial. La noción de
prueba de resistencia también se asemeja a la idea de "caso de prueba" en
ingeniería de software, que es una problemática única que puede
66 Filosofía del software

probarse con éxito y, por tanto, designa el código libre de ese error o
problema. Estas pruebas constituyen la base de la comprobación de la
"autenticidad" del software, ya que fallar las pruebas indica que el
Lectura y escritura de
c ó d i g o s 67
El "hecho" o realidad del software no se ha conseguido. Por tanto, para
ser incluido en una determinada "sociedad del código", éste debe
legitimarse (realizarse) mediante una serie de pruebas. El código es más
visible cuantas más conexiones tenga. Esto se hace eco de los trabajos de
Gabriel Tarde, sociólogo de principios del s i g l o XX, que soñaba
con seguir a los actores de una formación social a través de la
cartografía de las conexiones que establecían. Para Tarde, todo es una
asociación, "todo es una sociedad" (Latour 2002: 118). Este es el punto
de partida del análisis del software que quiero explorar. Esto nos
permitirá cartografiar los vínculos y las solidaridades que se forman
entre los programas informáticos y, por tanto, rastrear la forma en que
se materializan y se fabrican. Boltanski y Thévenot (2006) hacen una
distinción útil entre dos modos de prueba diferentes: (1) pruebas de
fuerza (épreuves de force), que problematizan por sí mismas las
condiciones límite y (2) pruebas legítimas (épreuves légitimes), que son
pruebas dentro de las condiciones límite. En una prueba de f u e r z a , es
aceptable movilizar cualquier tipo de fuerza. No se especifica nada de
antemano. Todo vale, con tal de que s e v e a coronado por el éxito
(esto podría considerarse como un código de pirateo). En una prueba
legítima, jugar según las reglas de la situación limita lo que se puede
hacer para tener éxito (esto puede pensarse como seguir procesos de
software legítimos). Una prueba legítima siempre debe probar algo
que se ha definido, presentándose como prueba de algo.
Para profundizar en la cuestión del código y poner de r e l i e v e el
elemento de la materialidad, utilizo la noción de Latour de "prueba de
fuerza" para ver cómo la materialidad del código, su obstinación y su
concreción se ponen a prueba en los concursos de programación
informática. Este enfoque es útil, ya que incorpora dimensiones tanto
discursivas como extradiscursivas en el análisis del código. Esto se debe
a que uno de los requisitos más importantes para los materiales que
componen un conjunto de programación es que superen las pruebas de
"requisitos" predefinidos. Éstos suelen identificarse en la especificación
de requisitos, que es esencialmente una descripción fina del software
que se va a crear. A partir de ahí se elabora una descripción gruesa,
normalmente en las fases de diseño, que es un esbozo detallado de gran
parte del procesamiento que debe llevarse a cabo y de las características
generales de la estructura, a veces mediante pseudocódigo o a través de
uno de los lenguajes formales como UML (Lenguaje Unificado de
Modelado) o Z. Sólo después de este punto comienzan realmente las
fases de creación de prototipos y pruebas y se escribe el código, pero
sigue siendo un proceso iterativo para construir la estructura detallada y
el contenido del sistema de software requerido.
Por ejemplo, es necesario superar una serie de pruebas antes de lanzar
68 Filosofía del software

el software al público. Cada etapa del ciclo de lanzamiento se materializa


Lectura y escritura de
c ó d i g o s 69
de diferentes formas, como compilación (en hardware), impreso (en
papel), probado (por humanos) o distribuido (en un soporte físico).
Como la mayoría del software sigue desarrollándose en una variante del
"modelo de cascada" de desarrollo de software que recorre un ciclo de
diseño-código-prueba-liberación de software, podemos trazar esta
materialidad como "pruebas de resistencia". Así, el software pasa por
una serie de fases que son iterativas con la intención de mejorar la
calidad del software con cada ciclo. Cada paso crea entidades físicas (por
ejemplo, documentación) y pruebas que refuerzan aún más la
materialidad del código. Algunos de los ciclos de desarrollo que se
utilizan son:
(i) Alfa, primero como pruebas de caja blanca, a veces llamadas pruebas
de caja de cristal, es donde se prueba la lógica interna del código. Una
vez completadas, las pruebas pasan a tratar los aspectos internos como
ocultos y comienzan las pruebas de caja negra, que pretenden
comprobar las relaciones externas con el código. Una vez finalizada la
prueba alfa, el código suele "congelarse" y se considera completo, sin
que se añadan funcionalidades importantes; (ii) Beta, que puede ser
abierta o cerrada al público, y que implica pruebas de usabilidad para
garantizar que se minimizan los problemas para los usuarios. Algunas
empresas, sobre todo las relacionadas con la web 2.0, utilizan esta
exclusividad para promocionar su software y aumentar la base de
usuarios; (iii) Versión candidata (RC), en la que el software ha alcanzado
el punto en el que está listo para su lanzamiento y se somete a una
última fase de pruebas para eliminar cualquier problema importante del
software. Esta versión suele considerarse "código completo" y no se le
añaden cambios significativos; y por último (iv) la versión para
fabricación, también conocida como versión para comercialización, en
la que el software está listo para su lanzamiento como producto final.
Cuando un programa informático se publica en CD o DVD, a veces se
denomina "versión gold" o "gold master", un término especialmente
asociado a Apple Corporation. Este término se utiliza porque la versión
maestra entregada a los fabricantes como versión final tendría la forma
de un disco dorado.
Sólo cuando se han superado una serie de pruebas se considera que el
código final, ahora compilado en software, es un "candidato a la versión
final" y, por tanto, puede entregarse a los usuarios como versión beta
(normalmente una versión previa a la versión final que aún puede
contener errores semimportantes) o como versión final candidata a la
versión final próxima a su lanzamiento. Cada etapa del proceso puede
entenderse en términos de la noción de "pruebas de resistencia", lo que
nos permite centrarnos en los requisitos reales que se exigen al código
en todas las fases de su evolución, a medida que se ensambla en la
70 Filosofía del software

versión candidata final como software de lanzamiento. En las secciones


siguientes quiero examinar las pruebas de fuerza demostradas en una
serie de ejemplos de programación, por ejemplo, en el ejemplo de
Microsoft que figura a continuación, veremos cómo Microsoft utiliza la
noción de una compilación diaria de todo el sistema operativo como
medio de probar la
Lectura y escritura de
c ó d i g o s 71
el hecho de que el sistema operativo funciona y avanza en su desarrollo.
A lo largo de estos estudios de casos, la intención es vincular el nivel
simbólico del programador alfabetizado con el requisito maquínico de
compilación y ejecución del software.

Código de lectura

El código fuente de Microsoft filtrado


En febrero de 2004, el código fuente de Windows 2000 se filtró
accidentalmente en la web, como "archivos [fechados] el 25 de julio de
2000. El código fuente estaba contenido en un archivo Zip de...
213.748.207 bytes, llamado windows_2000_source_code.zip, [y] había
circulado ampliamente por redes P2P" (Selznak 2004). Esto brindó a
cualquier internauta una oportunidad única de leer de cerca el software
escrito por los programadores de Microsoft. La mayor parte de la
atención se centró inmediatamente no en el código, sino en los
comentarios a todo color que explicaban su funcionamiento. Esto se
debió a varias razones: en primer lugar, la preocupación por la posible
infracción de los derechos de autor del código fuente de Microsoft y, al
no "leer" explícitamente el código, los programadores esperaban
protegerse manteniendo una "sala blanca" separada de ellos mismos y del
código real.1 En segundo lugar, el código contiene millones de líneas
muy complicadas y los comentarios son una forma de documentación que
a menudo constituye un primer paso en el proceso de comprensión.
Microsoft es famoso por compilar, o "construir", todo su sistema
operativo todos los días para comprobar que el código funciona y
eliminar problemas y errores lo antes posible en el proceso de
codificación. La compilación diaria también actúa como mecanismo
disciplinario para su personal, ya que les somete a ellos y a su trabajo a
una observación constante. Como todo el mundo sufre cuando falla la
compilación, existe una considerable presión entre compañeros para no
"romper la compilación" enviando código no probado o problemático.
Desde el punto de vista del análisis que estamos realizando aquí,
podríamos considerar la compilación como una importante "prueba de
fuerza" para la materialidad del software de desarrollo de Microsoft
Windows. Para formar parte del código fuente de Windows y, por lo
tanto, estar en la carrera para ser una parte liberable del sistema
operativo, se requiere que pueda ser materializado en la compilación a
través de la superación del proceso de compilación. Este proceso de
compilación implica tanto un aspecto material como social, (i) el código
debe compilarse en la máquina de compilación dentro de las
restricciones establecidas del proceso de compilación, que son
esencialmente una serie de pruebas de compilación; (ii) toda la
72 Filosofía del software

organización revisa entre pares el proceso de compilación y hacer que la


compilación falle es advertido por toda la comunidad de desarrolladores
y socialmente mal visto; (iii) la compilación diaria suele incluir una
serie de "pruebas de humo", o pruebas de verificación de compilación,
que proporcionan medios "superficiales y amplios" de evaluar las nuevas
versiones del software. Estas pruebas pueden incluir
Lectura y escritura de
c ó d i g o s 73
para garantizar que se ha compilado e incluido la versión correcta del
código, que funciona la comprobación básica de errores o que el
programa no bloquea el sistema o se bloquea a sí mismo al iniciarse. En
las fases posteriores de las pruebas, ya sean alfa o beta, se suelen llevar
a cabo pruebas más exhaustivas, normalmente a cargo de evaluadores
humanos especializados.
Al observar el código de estos archivos, se obtiene una visión del
proceso de compilación diario de Microsoft. Por ejemplo, en un mensaje
a los programadores que podrían cambiar su código sin pensar en las
consecuencias para el proceso de compilación, en el archivo
private\windows\media\avi\verinfo.16\verinfo.h, estaba

* ¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* ¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* !!!!!!! SI CAMBIAS TABULADORES POR ESPACIOS, TE MATARÁN!!!!!!!
* !!!!!!!!!!!!!!HACERLO JODE EL PROCESO DE
CONSTRUCCIÓN!!!!!!!!!!!!!!!!
* ¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Figura 3.1 Comentario del código fuente de Microsoft Windows (Selznak 2004)

Los programadores de Microsoft también revelaron su opinión


sobre varios momentos "imbéciles" del código en los que señalan
errores o fallos introducidos por otros programadores (podríamos
pensar en ellos como pruebas "suaves" de fuerza). Esto apunta no sólo
a prácticas de programación "estúpidas", sino a los problemas que
cualquier organización tendrá para gestionar proyectos con decenas
de millones de líneas de código fuente. No sólo existe el problema de
mantener el proyecto en la cabeza de cualquier individuo, sino la
complicación añadida de que el personal se marcha, la memoria
corporativa se agota y, además, se añade nuevo software a un
software antiguo que nunca se diseñó para ser extensible del modo
que habría sido útil para los desarrolladores posteriores. Por
supuesto, también habrá una dimensión de culpar a otros
departamentos o al equipo de software por sus decisiones "estúpidas"
en el diseño y la implementación. Este ejemplo demuestra la
necesidad de comunicación y de una buena planificación de alto
nivel de la arquitectura del sistema en cualquier gran proyecto de
software:

privadogenx\shell\inc\prsht.w:
// somos unos idiotas. Wiz97 sufrió un rediseño entre IE4 e IE5
private\shell\ext\ftp\ftpdrop.cpp:
Tenemos que hacer esto sólo porque Exchange es un imbécil.
74 Filosofía del software

private\shell\shdoc401\unicpp\desktop.cpp:
// Somos imbéciles. Cambiamos la interfaz IDeskTray entre IE4

private\shell\browseui\itbar.cpp:
// deberían arreglarse en las propias aplicaciones. ¡Idiotas!

Figura 3.2 Comentarios de "imbéciles" en el código fuente de Microsoft Windows


(Selznak 2004)
Lectura y escritura de
c ó d i g o s 75
Los documentos también mostraban casos en los que los empleados
de Microsoft se veían obligados a romper las convenciones de
programación y realizar "hacks", o arreglos poco elegantes del software
para sortear cuellos de botella estúpidos, restrictivos o problemáticos en
el código base existente. Ni que decir tiene que los programadores
profesionales no deberían recurrir a los "hacks" para que el código
funcione, ya que inevitablemente generan más problemas y requieren
más "hacks" para solucionarlos a largo plazo. Los "hacks" se
diferencian de los momentos "idiotas" en que son arreglos temporales
para hacer que las cosas funcionen. Los "hacks" también suelen
aplicarse en respuesta a una n e c e s i d a d urgente, por ejemplo,
cuando se ha identificado un problema importante en el código muy
cerca de la fecha de lanzamiento o se ha descubierto un fallo de
seguridad. Sin embargo, a veces no hay forma de evitar la necesidad de
un parche urgente para el código, aunque en contra de lo esperado se
convierta en una reparación permanente de la que pronto nos olvidamos.

rivate\ntos\w32\ntuser\client\dlgmgr.c:
// HACK DE LA MUERTE:

private\shell\lib\util.cpp:
// TERRIBLE HORRIBLE nO GOOD VERY BAD HACK

private\ntos\w32\ntuser\client\nt6\user.h:
* La magnitud de este hackeo se compara favorablemente con la
de la deuda nacional.

Figura 3.3 Comentarios de "pirateo" del código fuente de Microsoft Windows


(Selznak 2004)

Al leer el código fuente de Microsoft también se empiezan a


establecer conexiones con la economía política del desarrollo de
software en general. Por ejemplo, Microsoft utiliza ciertas llamadas a
funciones especializadas llamadas Interfaces de Programación de
Aplicaciones ( API) que se mantienen privadas e internas a la empresa.
Su propio software las utiliza para mejorar el rendimiento frente al
software de terceros rivales. Aunque no son técnicamente ilegales,
demuestran sin duda las ventajas del control monopolístico de una
plataforma de software que puede aprovecharse, por ejemplo, para
obtener beneficios,
76 Filosofía del software

privatemvdm\wow32\wcntl32.c:
// Estos mensajes no documentados son utilizados por Excel 5.0

private\windows\shell\accesory\hypertrm\emu\minitelf.c:
// Ah, la vida de los indocumentados. La documentación dice
// que estos tipos no validan, colorean, actúan como delimitador
// y se rellena con espacios. Incorrecto. Sí valida el color.
// Como tal es un delimitador. Si...

Figura 3.4 Comentarios "no documentados" en el código fuente de Microsoft


Windows (Selznak 2004)

Las características indocumentadas también pueden utilizarse para


atajar la programación permitiendo utilizar trucos en el software (como
se muestra en el segundo ejemplo anterior). De nuevo, se trata de
maniobras arriesgadas, ya que pueden modificarse fácilmente en el
futuro, y el hecho de ser indocumentadas por su propia naturaleza
significa que los propietarios del efecto indocumentado pueden no darse
cuenta de que otros podrían estar utilizándolo. Estos ejemplos dan una
idea clara del turbio mundo de la programación, sobre todo en sistemas
heredados y a gran escala, donde la programación diaria puede implicar
más descodificación, piratería y uso de funciones indocumentadas de lo
que cabría esperar de lo que en apariencia parecen prácticas de
programación profesionales.
Gran parte de la atención mediática sobre la filtración del código
fuente se centró, curiosamente, en la posibilidad de que los rivales
robaran o utilizaran el software. Por ejemplo, la BBC informó de que
"este acceso podría proporcionar una ventaja competitiva a sus
rivales, que conocerían mucho mejor el funcionamiento interno de la
tecnología de Microsoft" (BBC 2004). Esto es poco probable, ya que el
código fuente no sólo estaba incompleto, sino que además estaba muy
desfasado, y el software está en continuo y dinámico desarrollo, con
el árbol de código en constante estado de cambio. Apostar su empresa
por el uso de API privadas o funciones esotéricas o no documentadas
sería confiarla a la suerte y esperar que Microsoft no cambie algo más
adelante. Los propios programadores se lo pasaron en grande buscando
palabras malsonantes, elementos generales de código interesante y
comprobando si los rumores de malas prácticas y mala programación
eran ciertos (véase Slashdot 2004). Muchos de los comentaristas
destacaron la improbabilidad de que alguien encontrara algo
interesante que extraer del código de Microsoft, señalando la
diferencia entre tener el código fuente como repositorio textual y
conseguir compilarlo realmente. Cuando
Lectura y escritura de
c ó d i g o s 77
Si se tiene en cuenta que el código tiene millones de líneas y que el
proceso de compilación es, sin duda, idiosincrásico y específico de
Microsoft, está claro que descifrar este código supondría un reto para la
memoria de cualquier programador. La CNN informó de que el "código
filtrado de Windows 2000 contenía 30.915 archivos y la friolera de 13,5
millones de líneas de código" (Legon 2004); otros expertos han
calculado que esto equivale aproximadamente al 47% del código base
total de 29 millones de líneas de código (Jones 2004).
La filtración del código también dio lugar a divertidas parodias del
código fuente, como el fragmento siguiente,

if (detect_cache())
disable_cache();

si (fast_cpu())
{
set_wait_states(lots);
set_mouse(speed, very_slow);
set_mouse(action, jumpy);
set_mouse(reaction, sometimes);
}
/* printf("Bienvenido a Windows 3.1"); */
/* printf("Bienvenido a Windows 3.11"); */
/* printf("Bienvenido a Windows 95"); */
/* printf("Bienvenido a Windows nT 3.0"); */
/* printf("Bienvenido a Windows 98"); */
/* printf("Bienvenido a Windows nT 4.0"); */
printf("Bienvenido a Windows 2000");

if (system_ok())
crash(to_dos_prompt)
si no
system_memory = open("a:\swp0001.swp", O_CREATE);

Figura 3.5 Parodia del código fuente de Microsoft Windows (Baltimoremd s.f.)

Este fragmento hace referencia al hecho de que usuarios y


programadores se h a n quejado durante mucho tiempo del lento
funcionamiento del sistema operativo de Microsoft, por lo que, por
ejemplo, la parodia desactiva la caché, que ralentizaría el ordenador, y
ajusta la velocidad del ratón a 'very_slow'. El "código" también señala
sarcásticamente la genealogía de Windows en sus diferentes versiones
(por ejemplo, 3.1, 3.11, 95, etc.) e insinúa que cada nueva versión de
Windows es en realidad el mismo sistema operativo rebautizado (por
ejemplo, los comandos printf).2

Código de investigación climática


Otro ejemplo de cómo el código abierto y el crowdsourcing en Internet
pueden confluir de forma fascinante en torno al código fuente es la
aparición en Internet de más de 1.000 correos electrónicos privados que
contenían datos y código de la Universidad de Eastbourne.
78 Filosofía del software

Anglia sobre datos climáticos. Esto se convirtió en un asunto


preocupante, conocido como "climategate", una controvertida serie
de datos que se difundió cuando se robaron correos electrónicos de la
Unidad de Investigación Climática (CRU) de la Universidad de East
Anglia. En concreto, esto derivó en lo que se conoció como la
controversia del "Palo de Hockey". The Guardian explica que "el
gráfico del 'palo de hockey' muestra la temperatura media del planeta
e n los últimos 1.000 años. Durante los primeros 900 años hay poca
variación, como la varilla de un palo de hockey sobre hielo. Luego,
en el siglo XX, se produce un brusco aumento como la hoja del palo"
(Pearce 2010). Los datos y los correos electrónicos fueron
inmediatamente compartidos, comentados y objeto de un gran debate
y controversia debido a la forma en que los investigadores parecían
ser arrogantes con los datos. Dado que el CRU produce uno de los
cuatro registros de temperatura global más utilizados y que estos han
sido clave para las conclusiones del Grupo Intergubernamental de
Expertos sobre el Cambio Climático (IPCC), según las cuales la
superficie del planeta se está calentando y es muy probable que las
emisiones de gases de efecto invernadero de la humanidad sean las
responsables, es fácil entender por qué pronto podría estallar una
polémica sobre la percepción de sesgos en el método científico.

Aunque se concibió como un icono del calentamiento global, el palo


de hockey se ha convertido en algo más: un símbolo del conflicto
entre los principales científicos del clima y sus detractores. Los
contrarios lo han convertido en el centro de sus ataques durante una
década, con la esperanza de que al demoler el gráfico del palo de
hockey puedan destruir la credibilidad de los científicos del clima
(Pearce 2010).

Eric Raymond, un activista clave del software de código abierto y


crítico con las teorías del cambio climático, lo demostró mostrando
en su blog los datos y el código que procesa y aplica las series de datos
en el código FORTRAN robado al CRU y comentándolo,

Del archivo de código del CRU osborn-tree6/briffa_sep98_d.pro,


utilizado para pre parar un gráfico supuestamente de temperaturas y
reconstrucciones del hemisferio norte.
;
¡¡¡Aplique una corrección MUY ARTIFICA para la decadencia!!!
;
yrloc=[1400,findgen(19)*5.+1904]
valadj=[0.,0.,0.,0.,0.,-0.1,-0.25,-0.3,0.,-
0.1,0.3,0.8,1.2,1.7,2.5,2.6,2.6,$
Lectura y escritura de
c ó d i g o s 79
2,6,2,6,2,6]*0,75 ; factor de corrección
if n_elements(yrloc) ne n_elements(valadj) then message,'¡Uy!';
yearlyadj=interpol(valadj,yrloc,timey)
80 Filosofía del software

Esto, gente, es una flagrante manipulación de datos, sin pretensión


[sic] de lo contrario. Aplana un periodo de temperaturas cálidas en la
década de 1940-1930: ¿ven esos coeficientes negativos? Luego, más
adelante, aplica un multiplicador positivo para obtener un
espectacular palo de hockey a finales de siglo (Raymond 2009).

Aunque no es un comentario sobre la exactitud o validez de las


afirmaciones de Raymond, este ejemplo muestra la importancia de ver
el código y poder seguir la lógica a través de fragmentos de código que
pueden compartirse con otros lectores. Un gran número de comentarios
no tardaron en llegar a este post, criticando el código, comprobando los
datos y pidiendo aclaraciones sobre cómo el CRU había utilizado estos
datos. Pero la polémica no se quedó aquí, las críticas al código se
extendieron por Internet y los foros de debate, y muchos ojos se fijaron
en fragmentos del código fuente. Especialmente archivos como
"HARRY_READ_ME.txt" (Harry 2009), que contenía un comentario de
un programador sobre el proyecto, incluyendo sus pensamientos y
errores, lo que muchos consideraron una pistola humeante
(KinsmanThoughts 2009). Aunque más tarde se descubrió que, en
realidad, este archivo era bastante anodino.
Pero lo más importante, y este es un tema recurrente, es que el
código también puede descargarse, compilarse y ejecutarse, y el
procesamiento real de los datos analizarse para ver si resultados
como estos producen artefactos accidentales o deliberados que
distorsionan los datos. Esto no sólo es un claro ejemplo de la
naturaleza cambiante de la ciencia como actividad pública, sino que
también demuestra cómo la democratización de la programación
significa que un gran número de personas pueden leer y criticar el
código.
Tras una detallada investigación de siete meses, la Independent
Climate Change Email Review dirigida por Sir Muir Russell, antiguo
funcionario y ex vicerrector de la Universidad de Glasgow, se llegó a la
conclusión de que el rigor y la honestidad de los investigadores del CRU
como científicos no estaban en duda (Black 2010). Sin embargo, sí
comentaron la forma en que la ciencia debe defenderse cada vez más en
el ámbito público y poner a disposición sus datos y el código en que se
basan sus conclusiones para evitar este tipo de controversias en el futuro.
El comité señaló la nueva forma en que Internet plantea "cuestiones
importantes sobre cómo hacer ciencia en un ámbito tan polémico y bajo
nuevos niveles de escrutinio, especialmente por parte de una blogosfera
en gran medida hostil y a veces experta" (The Economist 2010b). No
obstante, la forma en que se desarrolló la controversia en Internet, con
muchos actores diferentes comprobando el código, criticándolo e
Lectura y escritura de
c ó d i g o s 81
intentando descubrir la exactitud de las proyecciones, demostró lo
importante que se está volviendo el código para nuestra comprensión
del mundo y para las respuestas políticas al mismo.
82 Filosofía del software

Escribir código

Para analizar las cuestiones que plantea la escritura de código, en lo que


queda de capítulo me centraré en dos estudios de casos críticos, cuyos
procesos nos permiten ver la forma generalizada en que el desarrollo de
software es una actividad reflexiva continua. Estos casos también nos
permiten ver cómo se demuestra la materialidad del código al atenerse
estrictamente a las pruebas legítimas prescritas para el código que se
desarrolla. En algunos casos se permite una creatividad considerable y
una flexión de las normas para lograr el diseño del sistema que se
requiere. En otros casos, la materialidad se demuestra precisamente
cuando se pueden aplicar pruebas de resistencia que socavan por
completo o eluden estas pruebas legítimas, y que pueden cambiar toda
la naturaleza del proceso de prueba y desarrollo.
El primer estudio de caso es el Underhanded C Contest, un concurso
en línea en el que se pide a los concursantes que envíen código que
oculte otro propósito dentro de un código fuente bastante mundano. El
segundo e s e l International Obfuscated C Code Contest (IOCCC), un
concurso para escribir el programa en C más oscuro/ofuscado posible
que sea tan difícil de entender y seguir (a través del código fuente)
como sea posible. Siguiendo las reglas del concurso, y poniendo a
prueba cada programa, que debe estar disponible para ser compilado y
ejecutado por los jueces (así como por los demás competidores y el
público en general mediante el open sourcing del código), se demuestra
que el código es material siempre que supere estas pruebas de
resistencia. Cada uno de estos concursos plantea una serie de requisitos
y pruebas que el código debe cumplir para que se le pueda calificar de
código.

El concurso de la C solapada
El Underhanded C Contest es un concurso de programación en línea en
el que los concursantes intentan crear un código que aparente realizar
una función, mientras que realiza otra de forma sutil y preferiblemente
invisible. El software debe tener un alto nivel en términos de
programación literaria, es decir, "el objetivo principal... es escribir
código fuente que pase fácilmente la inspección visual de otros
programadores" (XcottCraver 2008). Pero como explica la página web
del concurso,

En este concurso debes escribir un código que sea lo más legible,


claro, inno- centrado y directo posible, y que, sin embargo, no
cumpla su función aparente. Para ser más específicos, debe hacer
algo sutilmente maligno (XcottCraver 2008).
Lectura y escritura de
c ó d i g o s 83
El concurso se celebra desde 2005 y está organizado por el Dr. Scott
Craver, del Departamento de Ingeniería Eléctrica de la Universidad de
Binghamton. El código debe estar escrito en lenguaje de programación
C, ser compilable y presentarse de forma que pueda demostrarse tanto
textualmente, como código fuente, como mecánicamente, como proceso
ejecutable en la máquina tras la compilación. La clave de la
competencia subrepticia es que el comportamiento subrepticio tiene que
estar en el propio código. Por lo tanto, en estos programas se requiere
un fuerte elemento de engaño humano, porque en lugar de "piratear" un
protocolo, hay que engañar a un programador. El engaño puede adoptar
muchas formas, pero una de las mejores es asegurarse de que nada de lo
que haga el programador se salga de lo normal. Esto se basa en e l
hecho de que el programador/probador esperará cierto tipo de
comportamiento predecible del código de programación y esto puede
ser explotado por el programador deshonesto. Por ejemplo, si la salida
que resulta de la ejecución del programa no cumple los requisitos de lo
que se esperaría como "salida estándar", probablemente se consideraría
sospechosa. El objetivo es crear un comportamiento malicioso que pase
desapercibido en una prueba o revisión de código.
Aquí me centraré en el cuarto concurso anual (12 de junio de 2008-20
de septiembre de 2008). La razón para hablar de la edición de 2008 es
que en años anteriores los requisitos de programación solían ser
bastante complejos y esotéricos, mientras que en 2008 el requisito
consistía simplemente en borrar, o redactar, un archivo de imagen
estándar en el ordenador. La sencillez de los requisitos encubría una
tarea bastante difícil, a saber, redactar un archivo permitiendo al mismo
tiempo deshacer la redacción y mantener el código relativamente claro
para la revisión por pares. El concurso utilizaba una estructura de datos
digital denominada "archivo PPM en formato ASCII (P3)", lo que
significaba que el formato guardado del archivo de imagen estaba en un
formato textual que lo hacía más sencillo para el cálculo de pro-
gramación.
El concurso contó con más de 100 inscripciones de programadores y
el requisito formal era que las inscripciones,

escribir un programa en C corto y sencillo que redacte (bloquee)


rectángulos en una imagen. El usuario alimenta el programa con una
imagen PPM y algunos rectángulos, y la salida debería tener esos
rectángulos bloqueados (XcottCraver 2008).

La idea es que el contenido redactado del archivo de imagen no se borre


realmente. En el mejor de los casos, la imagen aparecería bloqueada,
pero de algún modo los bloques redactados podrían resucitar. Este es el
84 Filosofía del software

principio de la redacción con fugas, de modo que con un pequeño


esfuerzo los datos filtrados
Lectura y escritura de
c ó d i g o s 85
debería poder reconstruirse. Como parte de los requisitos formales,
también se especificó el código de línea de comandos que se necesitaría
para ejecutarlo, a fin de garantizar que la parte inteligente de la
programación tuviera lugar dentro del programa en C que se presentara,
en lugar de a través de misteriosos archivos por lotes u otro mecanismo.

gcc -o redactomatic evidentementeinnocentprogram.c

% redactomatic in.ppm > out.ppm


10 14 121 44
10 60 121 90
10 104 121 134
^D

Figura 3.6 Redactar la ejecución de la línea de comandos

Las reglas del diseño del código de redacción eran sencillas: (1) el
programa debe compilarse fácilmente; (2) el usuario puede introducir
valores que correspondan a los rectángulos que deben redactarse como
coordenadas x,y; (3) el usuario sale (^D) y se genera el archivo
(out.ppm). Como puede verse, estas son las condiciones límite para
demostrar la materialidad del código. Como parte de la prueba del
código, los jueces compilarían el código ellos mismos en una máquina
adecuada y realizarían la prueba con varios archivos de imagen.
Las pruebas legítimas, incluían el objetivo clave del concurso:
producir un archivo fuente que parezca muy inocente, y pase la
inspección informal del código. Las pruebas legítimas adicionales que
se utilizan para validar el software fueron: (i) "Los programas cortos
son inocentes, y más impresionantes. Si su archivo fuente tiene más de
200 líneas, no es probable que gane. Puedes esconder un semirremolque
en 300 líneas de C. En general, cuantos menos escondrijos, más
impresionados estaremos si puedes ocultar un comportamiento
malicioso" (XcottCraver 2008); (ii) "El comportamiento típico es
inocente. Los pasos inusuales e innecesarios levantarán cejas a menos
que puedas encontrar una excusa razonable para ellos". Esto hace que
este reto sea algo difícil, porque sólo hay un número limitado de formas
en las que un tipo puede borrar un rectángulo" (ibíd. 2008). También
existía la posibilidad de obtener puntos extra: (iii) se concedían puntos
extra si el error, una vez detectado, parecía un fallo inocente en lugar de
una codificación incorrecta deliberada; (iv) se concedían puntos extra si
el código seguía pareciendo inocente al colorear la sintaxis; (v) se
concedían puntos extra si la fuga de información era dramática.

Primer puesto: John Meacham


El ganador fue John Meacham, un programador d e California (Estados
86 Filosofía del software

Unidos). Presentó una entrada codificada de 55 líneas que tomaba


Lectura y escritura de
c ó d i g o s 87
el archivo de imagen, escaneaba los números y ponía a cero los píxeles
eliminados de la forma más obvia posible. El código sustituía los
números por ceros a nivel de caracteres. La filtración se debía a que los
píxeles de baja intensidad se sustituían por un "0" y los de alta
intensidad por un "00" o un "000". Esto era completamente invisible en
la propia imagen.

for(c = buf;*c;c++) {
if(isdigit(*c)) {
if(!ws) {// nuevo número, incrementar ubicación.
ws = 1; x++;
if(x >= anchura * 3) {
y++; x = 0;
}
}
if(x > rx * 3 && x <= (rx + rwidth) * 3 && y > ry && y
< ry + rheight)
putchar('0');
si no
putchar(*c);
} else {
ws = 0;
putchar(*c);
}
}

Figura 3.7 Concurso Underhanded C, obra ganadora de John Meacham

La forma en que se creó la función "underhand" consistió en utilizar


claramente el formato del archivo de imagen. Se trataba de un
formato de texto sin formato, con información básica de cabecera y
una lista de números separados por espacios en blanco, como "234 2
0", donde los números representaban la magnitud de los
componentes rojo, verde y azul de cada píxel que se mostraría en la
pantalla.
El programa redactor parecía simplemente reemplazar los valores
dentro del rectángulo objetivo por cero. Sin embargo, debido a la forma
en que el código procesaba el archivo carácter por carácter, es capaz de
filtrar con cuántos dígitos empezaba cada valor. Así, por ejemplo, "234
2 0" se convertiría en "000 0 0". Esto era completamente invisible al ver
el archivo PPM, todos los valores cuentan como cero en lo que respecta
al formato, pero al mirar el archivo original, se podía recuperar alguna
información sobre lo que había en la zona en blanco. Aunque así se
salvaba una cierta proporción de cualquier archivo de imagen, debe
quedar claro que es especialmente eficaz con los documentos en blanco
y negro, el formato de la mayoría de los archivos de imagen textuales.
Esto se debe a que en estos archivos en blanco y negro sólo se utilizan
los valores "0" y "255" y, cuando se redactan, es fácil leer el "0" y el
"000" como los valores correctos. También se puede escribir fácilmente
un pequeño fragmento de código para volver a convertir los "000" en
88 Filosofía del software

los "255" correctos.


Lectura y escritura de
c ó d i g o s 89

0 255 0 0 000 0
255 255 255 000 000 000
0 255 0 0 000 0

Figura 3.8 Concurso C manipulado, los contenidos se borran manteniendo 255


como longitud "000", lo que muestra cómo se conserva la información básica de la
imagen tras la redacción.

Como parte de su explicación del código y para legitimar el


aspecto de revisión por pares de la entrada, Meacham también
presentó una dramatización de la superación de la importantísima
inspección del código,

Spook: "Entonces, ¿por qué procesaste el archivo carácter por


carácter, en lugar de hacer el más obvio scanf("%i %i
%i",&r,&g,&b) para leer los valores?".
Yo: " Bueno, para hacer eso tendría que leer líneas enteras del
archivo. Ahora existe la función gets en C que hace eso,
pero tiene un conocido bug de desbordamiento de buffer
si la longitud de la línea excede el tamaño de tu buffer, así
que naturalmente usé la variante segura fgets de la
función. Por supuesto, con fgets, puedes simplemente
asumir que el tamaño de tu buffer es mayor que la
longitud máxima de la línea, pero eso introduce un sutil
bug si no lo es, puedes acabar dividiendo un número en
dos buffers, por lo que scanf leerá algo como 234 como
los dos números 23 y 4 si se divide después del segundo
carácter, de ahí la necesidad de considerar cada carácter
independientemente."
Spook: "Ah, por supuesto. Buen trabajo para detectar eso."
Yo: *snicker*

Segundo puesto: Avinash Baliga


La segunda entrada colocada utiliza un método diferente para lograr un
resultado similar, este es técnicamente interesante debido al uso de un
desbordamiento de búfer. Un desbordamiento del búfer se produce
cuando un programador escribe accidentalmente más allá del final de un
archivo o variable en la memoria adyacente del ordenador. En los
sistemas de producción estándar, este tipo de error puede causar grandes
problemas y, de hecho, es una forma clave de crear 'exploits' para
90 Filosofía del software

romper un sistema seguro (fue la técnica utilizada para hacer jailbreak al


iPod y al iPhone, por ejemplo). El 'bug' diseñado en esta presentación
está en la macro ExpectTrue (situada al principio del código) que
imprime en un pequeño buffer (pequeño porque está redefinido en
main() ) sobreescribiendo
Lectura y escritura de
c ó d i g o s 91

la máscara utilizada para poner a cero los datos con un "0×0a". Este
método de escritura permite que dos bits sobrevivan a la redacción,
con una intensidad lo suficientemente baja como para pasar la
inspección visual, pero lo suficientemente alta como para reconstruir
los datos redactados más tarde.

/* Macro de comprobación de
errores. */ #define
ExpectTrue(cond , msg )
_snprintf(buf, 255, "%d: %s", LInE , msg ); if
(!(cond )) {
fputs(buf, stderr);
exit(-1);
}
...
int main(int argc, char** argv)
{
píxel p = {{0,0,0}};
int izquierda = 0, arriba = 0, derecha = 0, abajo = 0;
int máscara = 0, x = 0, y = 0, z =
0; char buf[32] = {0};
...
ExpectTrue( copy_ppm(in, &out),
"Error: no se ha podido asignar la imagen de
salida.n");

Figura 3.9 Concurso Underhanded C, segundo puesto de Avinash Baliga

El jurado quedó claramente impresionado por esta propuesta y la premió,

puntos extra por puro rencor, ocultando el malvado


comportamiento en una macro de comprobación de errores. El
rencor siempre te dará puntos extra en el Concurso de C Intrusos.
En el análisis final, este tipo consigue puntos por estilo y pericia
técnica; el único problema es que enmascarar píxeles, en lugar de
ponerlos a cero, es una operación difícil de justificar (XcottCraver
2008).

Esto es interesante porque el programador utilizó un fragmento de


código de comprobación de errores para implementar realmente la
función encubierta. Esto naturalmente apela a la idea de que el mejor
lugar para ocultar una función de este tipo es en el lugar más
descarado del código, donde la mayoría de la gente esperaría que se
tomara el más alto nivel de probidad y cuidado.
Tercer puesto: Linus Akesson
Linus Akesson fue el tercer participante en el concurso. Empleó un
92 Filosofía del software

"importante principio de codificación poco limpio: hacer que el caso


común sea malo y el caso poco común, malo" (XcottCraver 2008). Este
ejemplo de programación se basa en el
Lectura y escritura de
c ó d i g o s 93
el hecho de que, aunque prácticamente todos los archivos PPM utilizan
valores RGB (rojo/verde/azul) de 8 bits, es decir, valores entre 0 y 255,
son posibles valores superiores, a saber, valores de 16 bits de 0 a 65535.
Esto permite al programador fingir que está comprobando estos valores
de 16 bits, mientras que en realidad está utilizando esta comprobación
para implementar la función encubierta.

#define BYTESPERPIXEL(fits8bits) (3 << (!fits8bits))


...
int main(int argc, char **argv) {
in = alloca(anchura * altura * BYTESPERPIXEL(256 > max));
out = alloca(anchura * altura * BYTESPERPIXEL(256 >
max));

fread(in, BYTESPERPIXEL(256 > max), width * height, stdin);

ptr = out;
for(y = 0; y < altura; y++) {
for(x = 0; x < anchura; x++)
{
for(i = 0; i < BYTESPERPIXEL(256 > max); i++) {
*ptr++ = *in++ & visibilidad_mask(x, y, argc, argv);
}
}
}
printf("P6n%d %dn%dn", anchura, altura, máx);
fwrite(out, BYTESPERPIXEL(max < 256), width * height, stdout);

Figura 3.10 Concurso Underhanded C, tercer puesto de Linus Akesson

Esta es quizás la presentación más complicada, ya que se basa en un


error de la macro BYTESPERPIXEL, debido a la falta de un par de
paréntesis. Esto significa que BYTESPERPIXEL (256>max) siempre
vale '3', y BYTESPERPIXEL (max<256) siempre vale '6'.
Esencialmente, las imágenes se asignan, leen y procesan con 3 bytes por
píxel y luego la salida se escribe con 6 bytes por píxel. El programa lee
en búferes creados en la pila con alloca(), por lo que el búfer de
entrada está justo después del búfer de salida, y el intercambio de
'256>max' con 'max<256' al final asegura que ambos búferes se escriben
en el archivo de salida. En este código, la macro BYTESPERPIXEL da
la falsa impresión de que el código soporta inteligentemente anchos de
bits mayores de los que probablemente experimentemos nunca. Un
pequeño efecto secundario de este truco, sin embargo, es que al intentar
redactar esas imágenes de mayor profundidad de bits el programa falla
por completo. No obstante, esa aparente compatibilidad con imágenes
de mayor tamaño ayuda a disimular el hecho de que el caso de los 8 bits
es capaz de filtrar información en el archivo.
Ahora pasamos de la ocultación de una nueva función en el código
al deseo de hacer el código fuente lo más ilegible posible. Se trata de
una técnica llamada ofuscación, que demuestra tanto la mutabilidad
94 Filosofía del software

del propio código fuente como el hecho de que un código fuente


ilegible puede seguir siendo ejecutable.
Lectura y escritura de
c ó d i g o s 95
Concurso internacional de código C ofuscado
El Concurso Internacional de Código C Ofuscado (IOCCC) es una
competición para programadores que tratan de escribir el programa C
con el aspecto más complicado posible en código informático. Se trata
de un código que resulte lo más difícil posible de entender y seguir para
un lector a través de la fuente textual. En otras palabras, la intención es
escribir código analfabeto, en lugar del código legible y claro que
defiende Knuth en su noción de programación alfabetizada. Sin
embargo, el objetivo no es escribir programas funcionalmente
complicados, sino que los programas presentados sean tan simples en su
funcionalidad como sea posible, pero tan difíciles de leer como sea
posible. El IOCCC lleva funcionando desde 1984 (con algunas
excepciones), y fue iniciado por Landon Curt Noll y Larry Bassel el 23
de marzo de 1984, mientras trabajaban en el grupo de portabilidad
Genix de National Semiconductor, escriben,

ambos estábamos en nuestras oficinas tratando de arreglar un código


muy roto. Larry había estado intentando arreglar un error en el
clásico shell Bourne (código C #definido hasta la muerte para
parecerse a Algol) y yo había estado trabajando en el programa
finger de los primeros BSD (una implementación de finger plagada
de errores, sin duda). Por casualidad, ambos salimos (al mismo
tiempo) al pasillo del edificio 7C para despejarnos... Empezamos a
comparar notas: "No te vas a creer el código que estoy intentando
arreglar". Y: ''Bueno, no puedes imaginar el nivel de daño cerebral
del código que estoy tratando de arreglar''. Así como: Después de
unos minutos volvimos a mi oficina, donde publiqué una llama en
net.lang.c invitando a la gente a intentar ofuscar el código fuente
UN*X en el que acabábamos de trabajar (Noll et al. 2009).

Las reglas del concurso establecen las líneas generales de la prueba de


fuerza del c o n c u r s o , y demuestran la actualidad del c ó d i g o e n
términos del concurso. Cada uno de los códigos presentados se compara
con los demás, pero deben poder ser compilados y ejecutados por los
jueces (así como por los demás concursantes y el público en general
mediante el código abierto). A continuación, se demuestra que el código
es correcto siempre que supere estas pruebas de resistencia. Para
orientar a los programadores en la elaboración de sus propuestas, los
organizadores del concurso incluyen en su sitio web una práctica
definición de "ofuscar":

Ofuscar: tr.v. -cated, -cating, -cates. 1. a. Hacer oscuro. b.


Oscurecer. 2. C o n f u n d i r : sus emociones ofuscaron su juicio. [Lat.
96 Filosofía del software

obfuscare, oscurecer : ob(intensivo) + Lat. fuscare, oscurecer <


fuscus, oscuro]. -obfuscation n. ofuscatory adj (Noll et al. 2009).

La ofuscación de código consiste en aplicar una serie de cambios


textuales y de formato a un programa, preservando su funcionalidad
pero dificultando su ingeniería inversa. Por lo general, el código
ofuscado es un código fuente que se ha hecho muy difícil de leer y
entender. Los "ofuscadores" lo consiguen alterando la estructura
textual y funcional que hace que un programa sea legible. También
utilizan preprocesadores de macros para ocultar la sintaxis y la
gramática estándar del cuerpo principal del código. Las ofuscaciones
también pueden crear efectos artísticos mediante sustituciones de
palabras clave o el uso, o no uso, de espacios en blanco, para crear
patrones o incluso imágenes completas a partir del código textual. Los
códigos ofuscados son ejemplos muy creativos de codificación que
emplean el lenguaje de programación "C".

Estos programas combinan una función ejecutable con una calidad


estética del código fuente. Desde 1984 se celebran concursos de
programación como el "International Obfuscated C Code Contest",
en el que compiten los mejores programadores de todo el mundo. El
reto consiste en emplear lenguajes de programación como C, C++ y
Perl bajo unas reglas especialmente restrictivas pero de forma
extremadamente creativa. Las reglas del concurso de código C son
muy sencillas: "Escriba, en 512 bytes o menos, el peor programa
completo en C". Los objetivos del concurso son presentar el
programa en C más oscuro y ofuscado, demostrar la importancia del
estilo de programación irónico, dar protagonismo a los compiladores
con código inusual e ilustrar las sutilezas del lenguaje C
(Digitalcraft.org 2006).

Para demostrar cómo se ofusca un programa, he aquí una sencilla


versión de seis líneas del código "hola mundo" escrita en código
fuente:3

#include "stdio.h"

int main() {
printf("¡Hola Mundo!");
return 0;
}

Figura 3.11 Ejemplo sencillo de programa en C

Se trata de una de las tareas de programación más sencillas que se


Lectura y escritura de
c ó d i g o s 97
piden a los programadores que se inician en un lenguaje, ya que muestra
cómo obtener una salida textual sencilla en la pantalla, pero también los
procesos de compilación y el aspecto.
98 Filosofía del software

del lenguaje. La forma más sencilla de ofuscar un programa es convertir


la cadena de texto "¡Hola Mundo!" en caracteres contenidos en un
formato de datos especial llamado array. Esto sólo hace que sea difícil
de leer, como se puede ver en el código idéntico a continuación, pero
ligeramente ofuscado para ocultar el texto,

#include "stdio.h"

void miFunción(int array[], int tamañoArray)


{ int;
for (i=0; i<tamañoArray; ++i) {
printf("%c", array[i]);
}
}
int main() {
int array[]={72,101,108,108,111,32,87,111,114,108,100,33};
miFunción(array,12);
return 0;
}

Figura 3.12 Programa C con caracteres ofuscados con llamada a función

Aquí, el "¡Hola, mundo!" se ha traducido en caracteres ascii


separados que contienen un número para hacer referencia a la letra. Así,
por ejemplo, "Hola" se convierte en una serie de números: 72 (H), 101
(e), 108 (l), 108 (l), 111 (o). De esto se deduce claramente que la
ofuscación es la sustitución de elementos textuales que son idénticos
para el ordenador, o que son computables igual, pero que para el ojo
humano son difíciles de leer o seguir. De hecho, uno de los trucos más
populares consiste en confundir al ojo haciendo que la estructura
parezca fragmentada o inconexa.
Ahora se pueden realizar una serie de cambios adicionales p a r a
dificultar la lectura del texto, entre los que se incluyen: (i) hacer la función
recursiva para que se llame a sí misma, una forma de pensar notoriamente
difícil en la experiencia cotidiana; (iii) usar índices y condiciones
especiales en el a r r a y , c o m o ocultar ciertos valores de
caracteres; (iii) usar numeración hexadecimal u octal en lugar de decimal,
como '0x64' o '0x6F'; (iv) renombrar las variables con nombres difíciles de
leer, como cambiar "integer" por " " o "arraySize" por "_0"; (v) renombrar
los nombres de las funciones para que sean difíciles de leer, de modo que
"myFunction" se convierta en "_"; y, por último, (vi) cambiar el formato
eliminando los espacios en blanco que ayudan a nuestros ojos a seguir el
texto y, en su lugar, rompen la lógica y la continuidad del c ó d i g o . De
este modo, la dimensión estética del código pasa a primer plano, junto con
las complejidades del estilo y la sintaxis de programación. No sólo es
n e c e s a r i o crear un programa adecuado para realizar una función, sino
también pensar en la presentación y el impacto visual. En este caso, por
Lectura y escritura de
c ó d i g o s 99
ejemplo, el resultado final sería esta serie de ofuscaciones:
100 Filosofía del software

#include "stdio.h"
_( ,_0,O_, ) {(O_<_0)?printf("%c",(O_==2)
||¿(O_==3)||(O_==9)? ++,O_++,108:*((int*)
+O_++- ) ),_( ,_0, O_, ): 0;}main(){int array
[]={72,'e',111,040,0127,0x6F,'r',0x64,041 };_(array
,
12
,
0
,
0
)
;
}

Figura 3.13 Programa C ahora ofuscado mediante cambios de texto y formato


confuso

Este ejemplo, sin embargo, es un intento muy básico y seguramente


no impresionaría a los jueces del concurso. Lo que buscan es un
verdadero talento y creatividad en el uso de las técnicas mencionadas,
junto con el tipo de conocimientos técnicos detallados que demuestren
una verdadera habilidad para la programación. Así, por ejemplo,
detallan en la descripción general del concurso el requisito:
(i) "Escribir el programa en C más oscuro/obscurecido"; (ii) "Mostrar la
importancia del estilo de programación, de forma irónica"; (iii)
"Destacar los compiladores de C con código inusual"; (iv) "Ilustrar
algunas de las sutilezas del lenguaje C"; (v) "Proporcionar un foro
seguro para el código C pobre. :-)" (Broukhis et al. 2009). Las reglas
técnicas del concurso son las siguientes:

1) La entrada debe ser un programa completo.


2) El tamaño del código fuente del programa debe ser <= 4096 bytes.
...
7) El programa debe ser de obra original.
...
10) No se permiten entradas que requieran interacción humana para
ser construidas.
...
12) Se fomenta en cierta medida el abuso legal de las normas.
13) Su fuente no puede contener octetos sin esconder con el bit alto
activado, es decir, su fuente no puede contener valores de octeto
entre 128 y 255 (Broukhis et al. 2009).

Este conjunto de normas para el concurso refuerza el argumento de que


la prueba no se centra en lo que hace el programa, sino en el aspecto del
código fuente, cuya lectura se utilizará para juzgar el mejor código,
aunque su materialidad queda demostrada por el requisito de que sea
compilable y ejecutable sin "interacción humana". Preferiblemente, debe
ser tan difícil de leer como sea posible, sin dejar ninguna pista al lector
Lectura y escritura de
c ó d i g o s 101
sobre la forma en que el programa está lógica y lógicamente programado.
102 Filosofía del software

construido funcionalmente. No obstante, debe ajustarse tanto a las


pruebas de fuerza como a las pruebas de legitimidad, que son el
fundamento de la materialidad del código, es decir, no debe infringir
ninguna norma. Sin embargo, estipulan la literalidad de la lectura de las
normas y fomentan el "abuso legal" de las mismas, de modo que aunque
deben respetarse las pruebas de resistencia, como el requisito de que el
código compile y funcione, las pruebas legítimas están abiertas a la
interpretación y a la elusión inteligente. Sin embargo, el hilo
conductor de las reglas y normas del concurso sigue siendo que el
código debe ejecutarse como un programa "normal" en lo que sea
que haga el programa. Además, el código se publica en Internet y se
presenta para que cualquier usuario pueda descargarlo, compilarlo y
ejecutarlo, sometiéndolo así a una especie de revisión por pares. En
otras palabras, el código siempre permanece "de código abierto" para
que pueda ser probado. Esta visibilidad del código y la
documentación completa sobre lo que hace, cómo compilarlo, qué
versión de GCC, etc., se incluyen junto con la decisión y el
razonamiento de los jueces. A continuación veremos algunos
ejemplos de ganadores anteriores o de participaciones destacadas en el
concurso.

Ejemplos de código ofuscado

Cada uno de los siguientes ejemplos muestra algunas de las mejores


propuestas para el concurso de código ofuscado. Han sido seleccionados
tanto por su capacidad técnica como por la forma en que han logrado
superar las pruebas de resistencia señaladas en las bases del concurso.
Sin embargo, lo más interesante quizá sea la capa adicional de
significado semiótico que muchos de los programadores deciden añadir
al código fuente en forma de imágenes visuales incrustadas en el
código, a menudo como una broma recursiva o un inciso. Creo que esto
es interesante por la forma en que la lectura atenta del código se hace
cada vez más difícil y, en consecuencia, la lectura dis- tante del código
se convierte en una apreciación de las imágenes visuales. También es
notable que los jueces apliquen las pruebas de fuerza en términos de
toda la entrada, a menudo remarcando el ajuste hermenéutico entre la
imagen visual y el texto y la función del código fuente subyacente.
Banks, cuya impresionante implementación de un simulador de vuelo
jugable, que se muestra a continuación, va acompañada de una
ingeniosa representación visual en el código fuente, es un claro ejemplo
de ello.

Entrada para 2004 por kopczynski4


Lectura y escritura de
c ó d i g o s 103
Este ejemplo es una implementación del reconocimiento óptico de
caracteres que detecta los caracteres 9, 8, 10 y 11. Si bien su escasez es
notable teniendo en cuenta lo que está diseñado para hacer, la brevedad
del código muestra la destreza de programación, pero también lo hace
en una sola línea de programación.
104 Filosofía del software

Código fuente
main(O){int I,Q,l=O;if(I=l*4){l=6;if(l>5)l+=Q-8?l-(Q=getchar()-
2)%2:l;if(Q*=2)O+="has dirtiest IF"[(I/-Q&12)-
l/Q%4];}printf("%d\n",8+O%4);}

Figura 3.14 Realiza el OCR de los números 8, 9, 10 y 11

Instrucciones de construcción
Para construir: make kopczynski
Comentarios del programador
El programa demuestra que no es tan difícil reconocer números. La
versión actual de una línea debería reconocer correctamente todos los
números del 8 al 11. (A menos que le des algunos casos muy
difíciles. Por ejemplo, no puede reconocer los negativos, los ceros
que tienen puntos o barras dentro, los dígitos deben estar separados y
los números deben estar "completos").
Comentarios del juez
¿Qué hay en una línea? Mucho cuando se ofusca de la forma en que
lo hizo Eryk Kopczynski. Este pequeño programa de una línea es una
obra de arte técnica excepcional, así como uno de los mejores
programas de una línea que hemos visto en años.
Compilar y ejecutar sin argumentos. Como entrada, dale una figura
gráfica ASCII 8, 9, 10 u 11 hecha de almohadillas y espacios, de
cualquier tamaño, forma u orientación (así es, un 9 al revés sigue
siendo 9 :-).

Entrada para 1984 de laman (imprime números en espiral,


dispuestos en columnas)5
Este ejemplo imprime en la pantalla números en espiral en columnas.
La broma 'recursiva' de que el código represente de forma visual la
acción que implementa es otra demostración del sentido del humor
hacker.
Código fuente

a[900]; b;c;d=1 ;e=1;f g;h;O;


main(k, l)char* *l;{g= atoi(* ++l); for(k=
0;k*k< g;b=k ++>>1) ;for(h= 0;h*h<=
g;++h); --h;c=( (h+=g>h *(h+1)) -
1)>>1;
while(d <=g){ ++O;for (f=0;f< O&&d<=g
;++f)a[ b<<5|c] =d++,b+= e;for( f=0;f<O
&&d<=g; ++f)a[b <<5|c]= d++,c+=e ;e= -e
;}for(c =0;c<h; ++c){ for(b=0 ;b<k;++
b){si(b <k/2)a[ b<<5|c] ^=a[(k -(b+1))
<<5|c]^= a[b<<5 |c]^=a[ (k-(b+1 ))<<5|c]
;printf( a[b<<5|c ]?"%-4d" :" " ,a[b<<5
|c]);} putchar( '\n');}} /*Mike Laman*/
Lectura y escritura de
c ó d i g o s 105
Figura 3.15 Imprime números en espiral, dispuestos en columnas
106 Filosofía del software

Comentarios del programador


NOTA: A algunos compiladores nuevos no les gustan las líneas 6 y
10 del código fuente, así que las hemos cambiado... ¡Espero que
tengas el embellecedor de C! El programa acepta UN argumento
positivo. Ver para creer, así que prueba cosas como:
laman 4
laman 9
laman 16
Este código debería darte vueltas.

Entrada de 2004 por arachnid6


El ejemplo de arachnid toma como entrada archivos ASCII formateados
en laberintos, que luego permite recorrer al usuario. De nuevo, una
"broma" recursiva es que el código fuente puede introducirse como
entrada para que el programa juegue de la misma manera.

Código fuente
#include <ncurses.h>/*****************************************************/
int m[256 ] [ 256 ],a
,b ;;; ;;; WINDOW*W; char*l="" "\176qxl" "q" "q" "k" "w\
xm" "x" "t" "j" "v" "u" "n" ,Q[
]= "Z" "pt!ftd`" "qdc!`eu" "dq!$c!nnwf"/** *** */"t\040\t";c(
int u , int v){ v [u] [v-
1] |=2,m[u][v-1] & 48?W][v-1 ] & 15]]):0:0;u?m[u -1][v]|=1 ,m[
u- 1][ v]& 48? W-1 ][v ]&
15] ]):0:0;v< 255 ?m[ u][v+1]|=8,m[u][v+1]& 48? W][ v+1]&15]]
):0 :0; u < 255 ?m[ u+1 ][v ]|=
4,m[u+1][ v]&48?W+1][v]&15]]):0:0;W][ v]& 15] ]);}cu(char*q){ devuelva
*q ?cu (q+ 1)& 1?q[0] ++:
q[0 ] -- : 1; }d( int u , int/**/v, int/**/x, int y ){ int Y=y -v, X=x -u;
int S , s ; Y< 0 ? Y =-Y , s, s=- 1 :( s=1);X<0?X=-X,S =-1 :(S= 1 ); Y<<=
1 ;X<==1; if(X>Y){
int f=Y -(X >>1 );; while(u!= x ) { f>=
0 ?v+=s,f-=X:0;u +=S ; f+= Y ;m[u][v]|=32;mvwaddch(w,v , u, m [u
][ v]& 64? 60: 46) ; if ( m [ u ][
v]&16){c(u,v);; ;;; ;;; return;}} }else{int f=X -(Y>>1);; while
(v !=y ){f >=0 ?u +=S, f-= Y:0
;v +=s ;f+=X;m[u][v]|= 32;mvwaddch(w,v ,u,m[u][v]&64?60:46);if(m[u
][ v]& 16) {c( u,v );
; return;;;}}}}Z( int/**/a, int b){ }e( int/**/y,int/**/ x){
int i ; para (i= a;i <=a
+S;i++)d(y,x,i,b),d(y,x,i,b+L);for(i=b;i<=b+L;i++)d(y,x,a,i),d(y,x,a+ S,i
); ;;; ;;; ;;; ;;; ;
mvwaddch(w,x,y,64); ;;; ;;; ;;; prefresh( w,b,a,0,0 ,L- 1,S-1
);} main( int V , char *C[
] ){FILE*f= fopen(¿V==1? "arácnido.c"/**/ :C[ 1], "r");int/**/x,y,c,
v=0 ;;; initscr (); Z(Z
(bruto
() ,Z( curs_set(0),Z(1 ,noecho()))),teclado( stdscr,TRUE));w =newpad
( 300, 300 ) ; para (x= 255 ; x >=0 ;x--
) para (y= 255 ;y>=0;y-- )m[ x][ y]= 0;x=y=0;refresh( );while
( (c= fgetc (f) )+1) {if(
0||c==10|| x== 256){x=0;y++;if(y==256 )break;;} else{m[x][y]=(c ==
'~' ?64 : c ==32 ?0: 16) ;;x ++;
}}para(x=0 ;x< 256;x++)m [x][0]=16 ,m[ x][ 255]=16;for(y=0
;y< 256 ; y ++) m[0 ][y ] = 16,
m[255][y] =16 ;a=b=c=0; x=y =1; do{v++;mvwaddch (w, y,x m[
x][ y]& 32? m[x ][y ] & 16?
0| acs_map[l[m[x][y]&15]]:46 : 32);c==0163&&!(m[x][y+1]&16)?y++: 0;c
== 119 ¡&&! (m[ x][
y- 1]& 16) y--:0;;c ==97 &&!(m[x-1][y]&16)?x--:0;c==100&&!(m[x+1
][ y]& 16) ? x ++:0 ;si( c==
3- 1+1 ){endwin( );; return(0) ;}x -a<5?a>S- 5?a-=S-5:(a=0):
0;x -a> S-5?a<255 -S* 2?a +=S
-5:(a=256-S):0; y-b<5?b>L-5?b-=L-5:(b =0) :0; y-b>L-5?b<255-L *2?
b+= L-5 :(b =256
-L) :0;e(x,y);if(m[x][y]&64)break;}while((c=getch())!=-1);endwin();cu(Q);
printf(Q,v);}

Figura 3.16 Visualizador/navegador de laberintos con visibilidad sólo directa


Lectura y escritura de
c ó d i g o s 107
Instrucciones de montaje
Para construir: make arachnid

Instrucciones del programador


Este programa acepta laberintos con formato ASCII como entrada, y los
muestra en pantalla para que el usuario los explore, completos con
Línea de Visión - no puedes ver partes del laberinto que tu avatar (el
'@') no podría haber visto. Los archivos del laberinto se interpretarán
con espacios ' ' como huecos, símbolos de tilde '~' (si los hay) como
salidas (que se representan como un estilo NetHack '<' una vez
cargado), y cualquier otro carácter como paredes. Alimente el programa
con su propia fuente para un laberinto por defecto. Ejecutarlo sin
parámetros de línea de comandos hará esto. En una simetría agradable,
el carácter constante '~' que reconoce las salidas a los laberintos de
entrada forma la salida al l a b e r i n t o p o r d e f e c t o . También se
ha proporcionado otro laberinto, 'maze1'. Este laberinto es de 255 ×
255, aproximadamente el laberinto más grande soportado, para el
particu-
de locos exploradores de laberintos.

Comentarios del juez


Lo divertido viene cuando te das cuenta de que el laberinto se
desplaza. El efecto visual general es bastante agradable (al menos en
algunas pantallas) y, bueno, es muy divertido. La navegación se
realiza mediante el uso de la formación "wasd" de la T invertida en
los teclados Qwerty.

Entrada para 2003 por cheong7


El programa de ejemplo de cheong simplemente toma un número y
devuelve la parte entera de su raíz cuadrada, por ejemplo la raíz
cuadrada de 9 es 3. A los jueces les gustó la limpieza del formato del
programa, así como su simplicidad funcional, pero apreciaron
claramente su "autodocumentación", señalando el hecho de que en el
propio código fuente se representa un símbolo de raíz cuadrada.

Código fuente

#include <stdio.h>
int l;int main(int o,char **O,
int I){char c,*D=O[1];if(o>0){
for(l=0;D[l ];D[l
++]-=10){D [l++]-=120;D[l]-=
110;while (!main(0,O,l))D[l]
+= 20; putchar((D[l]+1032)
/20 ) ;}putchar(10);}else{
c=o+ (D[I]+82)%10-(I>l/2)*
(D[I-l+I]+72)/10-9;D[I]+=I<0?0
:!(o=main(c/10,O,I-1))*((c+999
108 Filosofía del software
)%10-(D[I]+92)%10);}return o;}

Figura 3.17 Calcula la raíz cuadrada de precisión arbitraria


Lectura y escritura de
c ó d i g o s 109
Instrucciones de montaje
Construir: make cheong

Comentarios del programador


Compilar normalmente y ejecutar con un argumento, un número
entero con 2n dígitos. El programa devolverá la parte entera de su
raíz cuadrada (n dígitos). Por ejemplo,
> gcc -o cheong cheong.c
> cheong 1234567890
35136
> cheong 0200000000000000000000000000
14142135623730
>
La desviación de estas instrucciones provocará resultados indefinidos.
:-)

Comentarios del juez


El código fuente es bonito, compacto y autodocumentado, como
deberían ser todos los buenos programas. :-)

Entrada para 2001 por rosten8


El ejemplo de rosten añade un efecto de inercia al puntero del sistema X
Windowing. Esto significa que cuando se utiliza el puntero, el cursor
continúa moviéndose después de que el usuario haya dejado de mover el
ratón. Una vez más, los jueces destacan la forma en que el código
documenta visualmente el efecto del código ejecutado.

Instrucciones de montaje
Para construir: make rosten

Inténtalo:

./rosten 1.03
./rosten 1.00

Para abusar un poco, inténtalo:


./rosten 0,99

Comentarios del programador


Este programa está diseñado principalmente para hacer que su
interfaz de ventanas X sea más ofuscada. Intenta hacer algo con el
ratón (como usar un editor con el ratón en este programa) mientras se
está ejecutando. Si no estás seguro de lo que hace, mirar el código te
dará una idea.
110 Filosofía del software

Código fuente
#ifdef s
z
r(
){z
k=0,l
=0,n,x
XQueryPointer(i
XRootWindow (i,j),&m,
&m,&o,&p,&n,&n,( ghj)&n),(o
>=s(g)|||s(o
)<=0)&&(k=1),
(p>=h||p<=0)&&
(l=1),(e==1)&&(
c=o,d=p,e=0,1)||(
(k==0&&o-c-(z)(a+y
(a)*.5)!=0)&&(a=o-c
),(l^-1==-1&&p-d-(z)(
b+y(b)*.5)!=0)&&(b=p-d),a/=f,b/=f
k=0,l=0);(o >=s(g)||o<=0)&&(a=-a),(
p>=h||s(p)<=0) &&(b=-b),c=o,d=p,I(XWarpP
,ointer)(i,none,none,0,0,s
(g),h,(z)(a+y(a)*.5),(int)(
b+y(b)*.5 JJ(float B;int)C,D;
#else/*¡Caramba! algo ha */
#include<X11/Xlib.h>/*tomado a*/
#include<stdio.h>/*mordida enorme
o-*/ #include<stdlib.h>/*fuera de
la m-*/ #include<time.h>/*puntero
de casa!!!*/
#define H(a, b) (((a)&(7<<3*(b)))>>3*(b))
#define G(c,d) ((H(c,d)<<3*(d+1))|((H(c,d+1)<<3*d)|/*
XSetPointer(pantalla, pantalla,GREASY|BOUNCY)*/c&~(63<<3*(d))))
#defines (e) (G(G(G(G(G(e,(z)0),1),2),1),0),1)))
typedef int z;float a=0,b=0,c,d,f=1.03;z e
=s(512),g,h,j;
Display/**/*i;
#define y(X)((X>0)-(X<0))
#define xo ,p; Ventana m;
#define ghj unsignedint*
#define I(aa,bb)aa##bb
#define JJ(X)\
));return 0;}X
z r();int main
(z X,char**Y){
clock_t q=0;(X
==2)&&(f=atof(Y[1])),((i
=XOpenDisplay(0) )==0)&&(exit(
),1),j=I(Defa,
ultPantalla)(i
), g=s(I(Pantalla,
Anchura)(i,j)-1)
,h=I(Visualiza
rH,
ocho)(i,j)-1;
para(;;((I(clo,
ck)()-q)*100>(
CLOCKS_PER_SEC
))&&(r(),q=reloj()));}
#include F I L E
#endif

Figura 3.18 Hace que el puntero X del ratón tenga inercia o anti-inercia

Comentarios del juez


La fricción puede ser tu amiga si no te roza (ni a ti ni a tu ratón) de
forma incorrecta. :-)

Inscripción de bancos en 1998


Este último ejemplo de código C ofuscado fue el ganador del
Concurso Internacional de Código C Ofuscado (IOCCC) de 1998, en
la categoría "Best of Show". Se trata de un simulador de vuelo
escrito en 1536 bytes de código real. El código, una vez compilado y
ejecutado, permite al usuario pilotar un avión Piper Cherokee a través
Lectura y escritura de
c ó d i g o s 111
de diferentes paisajes. El programa tiene
112 Filosofía del software

sólo 2 kilobytes de código (escrito en 1536 bytes para ser exactos), con
una precisa dinámica de 6 grados de libertad, escenarios (3D) wireframe
cargables y un pequeño panel de instrumentos; funciona en sistemas
tipo Unix con X Windows. Destaca especialmente la estética del diseño:
el código fuente del programa dibuja la forma de un avión. Los jueces
identifican acertadamente la notable habilidad del programador y la
excelente pista visual de su función.

Código fuente
#include <math.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
doble L ,o ,P
,_=dt,T,Z,D=1,d,
s[999],E,h= 8,I,
J,K,w[999],M,m,O
,n[999],j=33e-3,i=
1E3,r,t, u,v ,W,S=
74,5,l=221,X=7,26,
a,B,A=32,2,c, F,H;
int N,q, C, y,p,U;
Window z; char f[52]
; GC k; main(){ Pantalla*e=
XOpenDisplay( 0); z=RootWindow(e,0); for (XSetForeground(e,k=XCreateGC (e,z,0,0),BlackPixel(e,0))
; scanf("%lf%lf%lf",y +n,w+y, y+s)+1; y ++); XSelectInput(e,z= XCreateSimpleWindow(e,z,0,0,400,400,
0,0,WhitePixel(e,0) ),KeyPressMask); for(XMapWindow(e,z); ; T=sin(O)){ struct timeval G={ 0,dt*1e6}
; K= cos(j); N=1e4; M+= H*_; Z=D*K; F+=_*P; r=E*K; W=cos( O); m=K*W; H=K*T; O+=D*_*F/ K+d/K*E*_;
B= sin(j); a=B*T*D-E*W; XClearWindow(e,z); t=T*E+ D*B*W; j+=d*_*D-_*F*E; P=W*E*B-T*D; for (o+=(I=D*W+E
*T*B,E*d/K *B+v+B/K*F*D)*_; p<y; ){ T=p[s]+i; E=c-p[w]; D=n[p]-L; K=D*m-B*T-H*E; if(p[n]+w[ p]+p[s
]== 0|K < f a b s ( W=T*r-I*E +D*P) | f a b s (D=t *D+Z *T-a *E)> K)N=1e4; else{ q=W/K *4E2+2e2; C= 2E2+4e2/ K
*D; N-1E4&& XDrawLine(e ,z,k,N ,U,q,C); N=q; U=C; } ++p; } L+=_* (X*t +P*M+m*l); T=X*X+ l*l+M *M;
XDrawString(e,z,k ,20,380,f,17); D=v/l*15; i+=(B *l-M*r -X*Z)*_; for(; XPending(e); u *=CS!=N){
XEvent z; XNextEvent(e ,&z);
++*((N=XLookupKeysym
(&z.xkey,0))-IT?
N-LT? UP-N?& E:&
J:& u: &h); --*(
DN -N? N-DT ?N==
RT?&u: & W:&h:&J
); }
m=15*F/l;
c+=(I=M/ l,l*H
+I*M+a*X)*_; H
=A*r+v*X-F*l+(
E=.1+X*4.9/l,t
=T*m/32-I*T/24
)/S; K=F*M+(
h* 1e4/l-(T+
E*5*T*E)/3e2
)/S-X*d-B*A;
a=2,63 /l*d;
X+=( d*l-T/S
*(.19*E +a
*.64+J/1e3
)-M* v +A*
Z)*_; l +=
K *_;
W=d;
sprintf(f,
"%5d %3d"
"%7d",p =l
/1,7,(C=9E3+
O*57,3)%0550,(int)i); d+=T*(.45-14/l*
X-a*130-J* .14)*_/125e2+F*_*v; P=(T*(47
*I-m* 52+E*94 *D-t*.38+u*.21*E) /1e2+W*
179*v)/2312; select(p=0,0,0,0,&G); v-=(
W*F-T*(.63*m-I*.086+m*E*19-D*25-.11*u
)/107e2)*_; D=cos(o); E=sin(o); } }

Figura 3.19 Simulador de vuelo escrito en 1536 bytes de código real

Instrucciones de montaje

Construir: hacer bancos

Para utilizarlo: cat horizon.sc pittsburgh.sc | ./bancos


Lectura y escritura de
c ó d i g o s 113
Comentarios del programador
Acabas de salir del mundo real y entrar en el virtual. Ahora está
sentado en la cabina de un avión Piper Cherokee, en dirección
norte, volando a 1000 pies sobre el nivel del suelo. Utilice el
teclado para pilotar el avión... En su pantalla, verá en la esquina
inferior izquierda tres instrumentos. El primero es el indicador de
velocidad; le dice a qué velocidad va en nudos. El segundo es el
indicador de rumbo, o brújula. El 0 indica el norte, el 90 el este, el
180 el sur y el 270 el oeste. El tercer instrumento es el altímetro,
que mide tu altura sobre el nivel del suelo en pies.
Características:
* El simulador modela un Piper Cherokee, que es un avión ligero
monomotor de hélice.
* El avión se modela como un cuerpo rígido de seis grados de
libertad, lo que refleja fielmente su dinámica (al menos en
condiciones normales de vuelo).
* Vuela por un mundo virtual en 3D sentado frente a tu consola X.
* Archivos de escenarios cargables.
* La pantalla Head-up contiene tres instrumentos: un indicador de
velocidad verdadera, un indicador de rumbo (brújula) y un
altímetro.
* ¡El avión nunca se cala!
* El avión nunca se queda sin combustible.
* ¡Vuela bajo tierra!
* Vuela a través de los edificios

Comentarios del juez


¿Qué podemos decir? Es un simulador de vuelo hecho en 1536
bytes de código real. Es una auténtica maravilla. Cuando la gente
dice que los límites de tamaño son demasiado estrechos, bueno,
podemos señalarles a éste. Este programa realmente va más allá.
***
Todos estos ejemplos han documentado de diversas maneras lo
importante que es para los programadores el acto de leer y escribir
código. Demuestran una fluidez de expresión, la capacidad de
elaborar y trabajar con código, e incluso un don para las imágenes
visuales utilizando caracteres ascii. En todos estos ejemplos, sin
embargo, la ejecución real del código es secundaria con respecto a la
fuente textual y, por tanto, sólo demuestra una parte de la distinción
entre código y software. En el próximo capítulo nos centraremos en
114 Filosofía del software

el código compilado y en cómo se entiende y examina su ejecución


como parte del proceso de ejecución del software.

También podría gustarte