Las especificaciones de los lenguajes, incluyendo las de C y C++, suelen estar escritas de forma poco precisa. Una herramienta llamada lint puede ayudarle a encontrar construcciones peligrosas y no portables en su código antes de que su compilador las convierta en errores de ejecución.
Cualquiera que haya escrito un programa ha tenido que depurar código. En muchos casos, después de mirar el código durante horas, finalmente nos damos cuenta de que hemos hecho algo estúpido como leer una variable no inicializada, o indexar más allá del final de un array. Con la experiencia, la incidencia de estos bugs «doh!» disminuye; pero todavía pueden ser extremadamente frustrantes y costosos.
Lo que necesitamos en esos momentos es un experto infinitamente paciente y analmente retentivo que inspeccione cada centímetro de nuestro código. Este experto debe ser más minucioso que cualquier compilador, y debe informar de forma totalmente desapasionada de todo lo que es potencialmente malo en nuestro código. Una herramienta de programación llamada lint es lo más parecido a este ideal. Si no sabes qué es lint, o no lo usas, te sugiero que sigas leyendo.
Lint es una herramienta similar a un compilador en el sentido de que analiza los archivos fuente C/C++. Comprueba la corrección sintáctica de estos archivos. Para limpiar un archivo llamado foo.c, uno suele escribir:
lint foo.c
en la línea de comandos. Naturalmente, sin embargo, también hay muchos interruptores opcionales en la línea de comandos.
Características estándar
Mientras que un compilador se ocupa principalmente de la generación de código, lint se dedica por completo a comprobar su código para una miríada de posibles defectos. La palabra clave aquí es posible. El hecho de que lint marque una sección de su código para su revisión, no significa necesariamente que se producirá un problema cuando compile ese código con su compilador particular.
Lint está diseñado para ser agnóstico con respecto al compilador y está, de hecho, frecuentemente en el negocio de centrar su atención en partes del código que podrían resultar en un comportamiento diferente dependiendo del compilador específico utilizado.
La lista específica de problemas que lint comprueba varía según la implementación y la versión de la herramienta. Sin embargo, la mayoría de los sabores de lint comprobarán al menos lo siguiente:
- Posible uso de variables no inicializadas
- Posible indexación más allá de los límites del array
- Dereferenciación de punteros nulos
- Asignaciones sospechosas (como if (a = b))
- Desajustes en los tipos de las variables (como foo declarado como double en un fichero y utilizado como long en otro)
- Combinaciones de tipos de datos potencialmente peligrosas
- Variables no utilizadas
- Código inalcanzable
- Ficheros de cabecera incluidos múltiples veces y/o innecesariamente
- Construcciones noconstrucciones portátiles
Lint comprueba tantas cosas, de hecho, que es habitual que la herramienta produzca tantos errores y advertencias como líneas de código tenga el archivo fuente de entrada. Esto es un gran rechazo para muchos usuarios potenciales, ya que su actitud tiende a ser «esta herramienta es tan exigente que es ridícula». Sin embargo, trabajar con cada advertencia y corregirla puede ser un ejercicio gratificante. Como ejemplo, considere este código aparentemente inocuo:
main(void){int i;for(i = 0; i
¿Cuál será el último número impreso cuando ejecute este programa? Si has respondido «100», estás equivocado. Este es un programa perfectamente válido, y compilará sin advertencia en la mayoría de los compiladores. Sin embargo, lint se quejará de algo. Si no puedes ver el problema a través de la inspección, entonces te sugiero que descargues el código de www.embedded.com/code.htm y lo ejecutes a través de tu depurador favorito. Nota, y una gran pista aquí: no escribas simplemente este programa en tu editor. Observe cuánto tiempo le lleva encontrar este problema y luego pregúntese si vadear las advertencias de lint no es tan malo.
Sacando el lint
A pesar del ejemplo ligeramente artificioso anterior, ¿qué tipo de beneficio en el mundo real puede esperar de abordar todas las advertencias producidas por lint? Mis experiencias en un proyecto típico que involucra un pequeño microcontrolador (el tamaño total del código es inferior a 32KB) incluyeron lo siguiente:
- Lint encontró dos o tres bugs directos-antes de que yo hubiera empezado a probar el código.
- Aprendí algo sobre el lenguaje C cada vez que lo ejecutaba.
- Mi código final era más limpio porque lint me informó de variables no utilizadas, macros y archivos de cabecera incluidos que podían ser eliminados con seguridad.
- Estaba mejor informado de los posibles problemas de portabilidad.
Dado lo anterior, probablemente no le sorprenderá saber que las organizaciones que se toman realmente en serio la calidad del código suelen insistir no sólo en que todo el código se compile sin advertencias (lo cual es relativamente trivial de lograr), sino también en que esté «libre de lint», es decir, que no genere advertencias con lint. Este es un criterio mucho más difícil de lograr.
Figura 1: Cómo encaja lint en el proceso de desarrollo
Vale la pena ver dónde encaja lint en el proceso de desarrollo. Mi flujo de diseño general se muestra en la Figura 1. Una vez que tengo el código que se compila, lo desvirtúo. Si el código pasa bien por lint, es muy poco probable que me avergüence en la revisión del código. Durante la fase de depuración, es normal que se hagan cambios en el código. Sin embargo, una vez depurado el código, y antes de pasarlo a la prueba de lanzamiento, normalmente vuelvo a pelar el código. ¿Por qué? Siempre me sorprende la cantidad de construcciones de código descuidadas que se producen cuando se está depurando el código. Lint es una gran herramienta para identificar ese trozo de código que se puso ahí para ayudar a depurar algo y luego se olvidó rápidamente.
Fuentes de lint
Lint es una herramienta estándar en la mayoría de los sistemas Unix. En el ámbito del PC, a menudo hay que salir a comprarla, o encontrar una versión gratuita o shareware. Si usted compra lint, puede estar seguro de que será el mejor dinero que haya gastado en su carrera de incrustado. La mayoría de las variantes de lint son relativamente baratas (menos de 1.000 dólares) y valen cada centavo.
Por cierto, puede que te preguntes qué tan bien maneja lint todas esas pequeñas y desagradables extensiones del compilador que son tan comunes en el desarrollo embebido. Esta es un área en la que los programas comerciales superan a las ofertas estándar. En particular, algunas versiones de lint permiten una considerable personalización de las reglas de lint, de manera que todas esas extensiones se manejan correctamente. En algunos casos, las definiciones del compilador son incluso suministradas por el proveedor de lint. En otros, puede obtenerlas del proveedor del compilador.
Si no tiene acceso a lint, pero está usando las herramientas GNU (en Unix o en un PC), simplemente use la bandera -Wall de gcc para lograr aproximadamente el 80% de la misma funcionalidad.
Así que, para todos los neófitos que hay, consiga una copia de lint, y úsela. Al menos, su jefe quedará impresionado con la madurez de su código. Para todos los hackers experimentados que no están usando lint, ¡cuidado! Los nuevos chicos que lo están usando podrían ponerte en evidencia.
Nigel Jones es un consultor en Maryland. Cuando no está bajo el agua, se le puede encontrar trabajando como un esclavo en una amplia variedad de proyectos integrados. Le gusta escuchar a los lectores y puede ser contactado en .