Repaso de C: reglas de alcance y variables estáticas

Reglas de alcance:

Las reglas de alcance son las reglas que determinan en qué parte de un programa en C se ve o se puede usar un nombre de variable o función. Recordemos que un programa puede constar de varios ficheros fuente, no sólo uno.

Como regla general, en C no se puede referenciar nada que no haya sido declarado antes. Esto es así porque el compilador de C sólo hace una pasada. Por tanto, cuando el compilador de C está a medias de procesar un fichero fuente, sólo conoce lo declarado desde el comienzo del fichero hasta ese punto.

Si se trata de un parámetro de entrada o de una variable local declarada al comienzo de una función, el alcance es la propia función. Si se trata de una variable local declarada a mitad de la función, el alcance es desde ahí hasta el final de la función.

Si se trata de una variable externa o una función, el alcance es desde el punto en que están declaradas hasta el final del fichero en que se encuentran.

Si se quiere usar una variable externa declarada en otro fichero, entonces hay que usar extern para indicar que se trata de una variable global, y por tanto accesible, pero declarada en otro sitio.

Variables y funciones estáticas:

Las reglas de alcance anteriores se pueden modificar con la palabra reservada static, que se puede aplicar a variables y a funciones.

Cuando una variable global / externa se declara como static, entonces esa variable sólo está disponible desde las funciones del archivo en que está declarada. Es una forma de limitar el alcance de las variables globales.

Igualmente, cuando una función se declara como static, ésta sólo se puede llamar desde el fichero en que está implementada. Nuevamente, es una forma de limitar el alcance de las funciones.

Por último, cuando la palabra reservada static se aplica a una variable local a una función, lo que ocurre es que esa variable mantiene su valor entre llamadas.


Código de ejemplo: alcance

Repaso de C: funciones, variables externas y estructura de un programa

Funciones:

Una función es un conjunto de instrucciones relacionadas entre sí y que implementan una funcionalidad concreta y autocontenida.

Las funciones constan de:

  • Un prototipo, que es opcional.
  • Una definición o implementación.

El prototipo sólo es necesario si la función se utiliza, es decir, se llama, antes de ser definida. Consiste en el nombre de la función, su valor de retorno y sus parámetros. Los parámetros se suelen documentar con tipo y nombre, aunque para el prototipo es suficiente con el tipo.

Un ejemplo de prototipo de función sería así:

Y luego está la definición o implementación de la función, que es la función propiamente dicha. La definición consta de nombre, valor de retorno, parámetros (tipo y nombre), y cuerpo, que constará de un conjunto de instrucciones.

No todos estos elementos son obligatorios. En realidad, sólo el nombre lo es. El retorno, los parámetros, e incluso el cuerpo son opcionales (aunque no tiene mucho sentido una función vacía, es posible hacerla).

Un ejemplo de implementación de función sería así:

No es lo mismo el tipo void, que significa que no hay parámetros o retorno, que no poner tipo, en cuyo caso se sobreentiende que es int. No se considera buena práctica apoyarse en estos tipos implícitos.

Lógicamente, la implementación tiene que concordar con el prototipo, en el sentido de usar el mismo nombre de función y los mismos tipos de parámetros y retorno. Si no fuera así, el compilador se quejaría.

La comunicación entre la función llamante y la función llamada es mediante los parámetros y el retorno. Al llamar, los parámetros se convierten en variables locales a la función, a las que se copia el valor de los parámetros (paso por valor, con la excepción de los arrays y las cadenas que se pasan por referencia o puntero).

La comunicación en sentido contrario es mediante el retorno, que se produce cuando la función ejecuta la instrucción return. La función llamante puede usar ese retorno o prescindir de él.

Variables externas:

Las variables externas ya las hemos introducido en alguna entrada anterior. Son variables que no se definen dentro de una función y, por tanto, son globales al programa. En principio, son visibles en todas las funciones del programa, salvo que se declaren como static, en cuyo caso sólo se ven desde el fichero en que están declaradas.

Las funciones son, en cierto modo, siempre externas, ya que C no permite definir funciones dentro de otras funciones.

Otra variante del main() anterior usando una variable externa sería así:

Como se puede observar, la variable externa o global a es visible desde main().

Por tanto, otra forma de comunicación entre un programa o función llamante y una función llamada es mediante las variables externas que, al ser globales al programa, son visibles desde todas las funciones (en principio).

Estructura de un programa en C:

Las funciones son la abstracción principal de un programa en C. Permiten dividir un problema complejo en varios problemas más sencillos, reutilizar código y crear niveles de abstracción.

Por tanto, un programa en C básicamente consiste en un conjunto de variables externas y funciones que se organizan en uno o varios ficheros, que se compilan por separado.

Una de esas funciones debe ser la función main(), que es donde empieza la ejecución del programa.


Código de ejemplo: funciones