¡Aprendiendo C99 con UpVent!

Conforme pasan los años los lenguajes de programación existentes mejoran constantemente e incluso se desarrollan nuevos. Sin embargo la gran mayoría de los lenguajes modernos comparten un antecesor en común. Este es el lenguaje de programación C.

En esta serie de blogs enseñaremos un poco de la historia del lenguaje de programación C, como escribir programas en el mismo y el uso que tiene en el mundo real. Así como crear pequeños programas que nos ayuden a entender el funcionamiento del mismo.

Cabe destacar que escribiremos código estándar en C, por lo que no utilizaremos bibliotecas externas como conio.h o similares, pues deseamos que nuestro código sea lo más flexible y portable posible.

Algunos datos importantes del lenguaje de programación C:

  • C fue desarrollado en los laboratorios “Bell” como un lenguaje de programación multipropósito.
  • C es el lenguaje de programación que se utilizó en el desarrollo del ahora descontinuado sistema operativo UNIX. Siendo ahora muy utilizado en plataformas UNIX-like como MacOS, Gnu/Linux, *BSD, etc.
  • Es un lenguaje de programación de ‘alto nivel’ de tercera generación, particularmente bueno produciendo código rápido y eficiente.
  • Suele confundirse como un nivel de “Bajo y alto nivel” o como un “Ensamblador de alto nivel” por razones como poseer estructuras de control al mismo tiempo que herramientas que permiten la manipulación de la memoria usualmente encontradas en lenguajes de bajo nivel.
  • Es un lenguaje altamente portable y fácil de mantener (Si el código está bien escrito, por supuesto)

Programas utilizados para estos tutoriales

Escribir una guía de instalación de los compiladores y las herramientas de programación está fuera del alcance de este tutorial, sin embargo compartiremos el conjunto de herramientas que utilizaremos al momento de escribir este blog:

  • Editor de texto: Gnu Emacs 27
  • Compilador: gcc 9.2.0
  • Terminal: Bash
  • Emulador de terminal: Tilix

¡Hola Mundo!

Vamos a empezar con la costumbre de todo programador al momento de iniciar su travesía por un lenguaje nuevo. El famoso programa “Hola Mundo”.

Un “Hola Mundo” en C se vería de la siguiente manera (No te preocupes si no lo comprendes, lo explicaremos paso a paso).

#include <stdio.h>

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

Antes de describir este programa línea por línea debemos tener en cuenta:

  • TODA sentencia en C termina con un punto y coma (;), los saltos de línea no son importantes excepto en los controles del preprocesador. Las líneas en blanco siempre serán ignoradas
  • TODA función en C deberá llevar paréntesis luego de su nombre ()
  • Las llaves agrupan sentencias y son el equivalente estructurado de las palabras “BEGIN” y “END” en lenguajes estructurados como PASCAL o como los algoritmos escritos a mano.

Ahora si, comencemos a desglosar nuestro “Hola Mundo” línea por línea:

#include <stdio.h>

Esto es un control de preprocesador, le dice al compilador que tiene que hacer antes de compilar el código que deseamos, específicamente esta línea le indica al compilador que queremos incluir el contenido de la biblioteca estándar de C dentro de nuestro programa, más específicamente algo llamado cabecera (por ello la extensión .h, por “header“). Las cabeceras usualmente constan de declaraciones de funciones, macros y tipos de datos. Todos ellos elementos que analizaremos más tarde, por ahora solo debes de saber que para acceder a ellos deberás incluir la cabecera que los contenga, esta cabecera contiene la función printf que observamos más abajo. Esto es un ejemplo del uso de cabeceras, pues printf se encuentra en la cabecera stdio.h y necesitamos añadirla al preprocesador para poder hacer uso de ella.

int main()

Esta línea es lo que conocemos como una definición de una función. Declara el nombre de la función, el tipo y el número de argumentos que espera.

y el tipo de dato que se desea que la función regrese, en este caso un tipo de dato entero (int). Todo programa en C comienza ejecutando la función main.

Las definicones de funciones contendrán tanto las definiciones de datos como instrucciones de código que se ejecutarán cuando el programa corra sobre nuestra máquina.

Todas las sentencias ejecutables deberán estar dentro de definiciones de funciones, además es obligatorio que todo programa en C contenga una función llamada main, cuando el programa sea ejecutado, main será la primer función en ser ejecutada.

En el caso de la función main existe el debate de como escribirla, es decir, si escribirla como:

  1. int main()
  2. int main(void)
  3. void main()
  4. void main(void)

En el caso de las 4 opciones recomendamos la número 1. ¿Por qué? simple, es la forma tradicional de escribir la función main en C. Además de que las 4 funciones al ser compiladas con GCC producen el mismo código de ensamblador.

Podrían argumentar que añadir void a la lista de argumentos es para evitar pasar argumentos a la función main de forma errónea, de igual forma con el tipo de dato de la función, cambiando el int a void. Desconocemos las razones de por que un programador (a menos de que el mismo haya ingerido sustancias nocivas para la salud) querría llamar a su función main con argumentos que no sean de línea de comandos al igual que no devolver un entero como código de salida al finalizar la ejecución de su programa.

{
        printf("Hola Mundo");
        return 0;
}

Como lo dijimos anteriormente, las llaves {} indican el inicio y final de un bloque de código, en este caso de una función. La línea printf("Hello World"); llama a la función printf() incluida en la cabecera stdio.h, su función es imprimir una cadena de texto hacia la salida estándar es decir la pantalla, terminal o consola, la cadena que deseemos imprimir deberá estar rodeada por comillas dobles "" y deberá estar dentro de los paréntesis ("") para ser considerada como válida. En este caso "Hola Mundo" será la cadena que deseamos imprimir, en el lenguaje de programación C TODAS LAS CADENAS deberán estar rodeadas por comillas dobles "..."

Finalmente tenemos la línea return 0;. Cuando definimos la función main la declaramos como una función que retornaría un int (entero). En este ejemplo estamos retornando un número entero con valor de 0, el cual se utiliza para indicar que todo el programa se ejecutó satisfactoriamente. Después de ejecutar la sentencia return 0; el programa se detendrá.

De nuevo, hay quienes debaten sobre el uso del return 0; en la función main. Sin embargo, caemos bajo la misma historia, el compilador produce el mismo código de ensamblador se añada o no. La razón de esto es que el compilador de C desde el estándar C90 añade al final de la función main (y solo de la función main) la sentencia return 0; por lo que ponerla o no ponerla da exactamente igual. Sin embargo recomendamos incluirla en tu código para mantener un estilo de código constante y limpio.

Compilando el programa

Luego de una larga explicación toca jugar con el compilador de C, en este caso gcc.

Para ejecutar el programa tendremos que tener a la mano nuestro archivo main.c (puede llamarse de otra forma) pues este se compilará en un ejecutable llamado “hello” en los sistemas UNIX-like o “hello.exe” en sistemas tipo Windows.

GCC (Acrónimo para “Gnu Compiler Collection”) es una colección de compiladores ampliamente utilizada, principalmente para compilar programas de C. Para usarlo tendremos que abrir nuestro emulador de terminal, navegar utilizando la consola hacia donde se encuentre nuestro archivo main.c y ejecutar la orden:

gcc main.c -o hello

Si no tenemos errores en nuestro código fuente (main.c) el compilador creará un ejecutable con el nombre que le dimos luego de utilizar la opción -o del compilador.

Pro tip: Si queremos escribir un código más depurado, limpio y poco propenso a errores podemos utilizar las opciones de mostrar advertencias extra para identificar problemas que podrían causar que nuestro programa falle o produzca resultados inesperados. No son particularmente necesarias para programas simples, pero esta sería la forma más correcta de utilizarlas:

gcc --std=c99 -Wall -Wextra -Werror -Wpedantic -o hello main.c

Estas opciones extra nos ayudarán de las siguientes maneras:

  • -Wall: Habilita todas las advertencias sobre el código actual que el compilador considere como “cuestionables”
  • -Werror: Convierte todas las advertencias en errores y el programa no compilará hasta que todas sean arregladas.
  • -Wpedantic / -pedantic: Mostrar todas las advertencias requeridas para cumplir con un estándar ISO C y ISO C++. Además de rechazar los programas que utilicen extensiones prohibidas, etc.
  • -std=c99: Especifica la versión del estándar que el compilador utilizará, este funciona en conjunto con pedantic.

Una vez compilado el ejecutable podrá correr en nuestra máquina ejecutando la orden ./hello si es un sistema tipo UNIX o dando doble click en el ejecutable si nos encontramos en Windows. El programa abrirá una consola, ejecutará la orden “Hola Mundo” y finalmente se cerrará.

¿Aprendiste algo nuevo hoy? Si te gustó el blog déjanos tus comentarios, síguenos en nuestras redes sociales y compártelo con tus amigos. Espéranos en la segunda entrega de “Aprendiendo ANSI C” ¡Nos vemos pronto! 😀

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

A %d blogueros les gusta esto: