Lenguaje C: ¿Un programa sin función main?

Publicado por Diego Córdoba en

En este artículo vamos a jugar con algunos conceptos de programación en lenguaje C, para que nuestro código C corra sin declarar la función main de manera explícita.


Analicemos el siguiente segmento de código escrito en Lenguaje C:

#include<stdio.h>
#define decodificar(j,u,n,c,o,T,I,C) c##j##n##u
#define mensaje decodificar(a,n,i,m,a,r,s,e)
int mensaje(){
    printf("Hola JuncoTIC.com\n");
}

Ahora compilemos y veamos si corre:

diego@cryptos:/tmp$ gcc prueba_main.c
diego@cryptos:/tmp$ ./a.out
Hola JuncoTIC.com

Funcionó correctamente… ahora la pregunta es: ¿Puede compilar y enlazar un código escrito en Lenguaje C sin función main?

La respuesta es SI… y NO, simultáneamente 😀

Todo código escrito en lenguaje C debe poseer una función main para que pueda enlazarse y ejecutarse, ya que de otra forma no hay compilador que pueda generar un binario ejecutable válido… de eso no hay duda, es de manual.

Lenguaje C: analizando las macrosc clang lenguaje c programming programacion

Entonces… ¿por qué el código anterior sí se ejecuta sin problemas? Este código claramente no tiene una función main definida explícitamente, y sin embargo funciona sin ningún inconveniente.

Y la respuesta está en las macros definidas (#define) en las primeras líneas de código.

Las macros creadas con la directiva de preprocesamiento #define son la clave del funcionamiento de este código.

¿Qué es lo que hacen estas macros en lenguaje C?

Las directivas de preprocesamiento, como todo programador C/C++ sabe, permiten ejecutar líneas de código de preprocesador antes de pasar a la compilación y posterior enlace/link de nuestro programa con las bibliotecas del sistema.

El operador ## permite, a nivel de preprocesamiento, pegar tokens o contenidos entre si, antes de compilar. Así podemos unir dos o más caracteres entre si, formando nuevas palabras que serán compiladas en el proceso de compilación.

Analicemos la línea 2 del programa anterior:

#define decodificar(j,u,n,c,o,T,I,C) c##j##n##u

¿Qué hace el preprocesador con esta directiva?

Simplemente concatena cuatro caracteres para realizar la sustitución. De los argumentos que recibe la macro-función decodificar, a saber, j, u, n, c, o, T, I, y C, concatena el cuarto carácter (c) con el primero, (j), luego el tercero (n), y por último el segundo (u), formando la palabra cjnu.

Ahora miremos la tercer línea de código:

#define mensaje decodificar(a,n,i,m,a,r,s,e)

En esta línea el preprocesador reemplaza la palabra mensaje con la expresión decodificar(a, n, i, m, a, r, s, e). De acuerdo con la macro definida en la línea anterior, el argumento debe ser expandido en la concatenación de los caracteres 4to, 1ro, 3ro y 2do. Aquí, en la serie de argumentos de la macro decodificar, es decir, en (a, n, i, m, a, r, s, e), los caracteres 4to, 1ro, 3ro y 2do son, respectivamente m, a, i, n.

Al concatenarlos, sí, obtenemos main, de modo que la línea int mensaje va a ser reemplazada, a nivel de preprocesamiento (antes de pasar a la compilación) como int main.

¿Y si pre-procesamos a ver qué sale?

Imaginemos que pudiéramos pre-procesar el código anterior, y ver qué es lo que realmente se está compilando… bah, dejémonos de imaginar, y pre-procesemos, sin compilar, el código… veamos la magia:

gcc -E prueba_main.c -o prueba_main.i

El código resultante, prueba_main.i, es el programa pre-procesado y previo a la compilación. Esto lo obtenemos gracias al modificador -E del compilador GCC.

La salida será extensa, principalmente por la inclusión de la cabecera stdio.h… pero si vemos al final del código qué es lo que tenemos, vamos a apreciar algo similar a esto:

int main(){
    printf("Hola JuncoTIC.com\n");
}

Sí señores, el código que va a compilarse finalmente sí tiene una función main declarada.

Conclusión

Como conclusión, no existe código funcional en lenguaje C (estándar ANSI) que pueda compilar, enlazar y correr sin una función main. En este ejemplo hemos ocultado la definición del main utilizando un juego de directivas de preprocesamiento y sustituciones, que transforman la palabra «mensaje» en «main«.

Quizás pueda interesarte:

Espero que les resulte de utilidad!

Como siempre, cualquier duda o consulta pueden contactare.

Hasta la próxima!


¿Preguntas? ¿Comentarios?

Si tenés dudas, o querés dejarnos tus comentarios y consultas, sumate al grupo de Telegram de la comunidad JuncoTIC!
¡Te esperamos!


Diego Córdoba

- Ingeniero en Informática - Mg. Teleinformática - Tesis pendiente - Docente universitario - Investigador