Este post es similar en temática a mis posts de OOP y Javascript Global Variables Weirdness salvo que sobre C.

Variables Automáticas

Se utilizan dentro del contexto de un bloque de código. Se inicializan y destruyen cuando termina el código de ese bloque. El típico ejemplo es las variables dentro de una función.

int main() {
	double i;
	.......
	my_function();
	....
}
int my_function() {
	int i = 15;
	......
}
En este ejemplo, la variable i de la función my_function es independiente de la i de la función main.

Variables Globales

Son accesibles y compartidas por todas las funciones definidas dentro de un archivo. Ej:

#include <stdio.h>
int i = 0;
int main() {
	printf("%d ", i);
	i++;
	my_function();
	printf("%d ", i);
}
int my_function() {
	printf("%d ", i);
	i = 15;
}
Imprime

0 1 15

Variables Externas

Si se quiere utilizar una variable global definida en un archivo externo, es necesario declararla usando extern . Ej:

Archivo vars-1.c


int i = 15;

Archivo vars-2.c


#include <stdio.h>
extern int i; 

int main() {
	printf("%d ", i);
	i++;
	printf("%d ", i);
	return 1;
}
Nota: Para compilar múltiples archivos ver Compiling multiple source files. En este caso se uso: gcc -Wall vars-1.c vars-2.c -o "vars" Se podría haber usado la variable dentro de un bloque de código, por ejemplo una función, para lo que es necesario hacer un archivo de header:

Archivo vars.h

void my_function();

Archivo vars-1.c


int i = 15;
char ch = 'a';

Archivo vars-2.c


#include <stdio.h>
#include "vars.h"
extern int i; 

int main() {
	printf("%d ", i);
	i++;
	printf("%d ", i);
	my_function();
	return 1;
}
void my_function(){
	extern char ch;
	printf("%c ", ch);
}
El archivo de header solamente tiene el prototipo de la función.

Variables Estáticas

Hace que una variable global limita su alcance al archivo en el que esta declarada. Por otro lado usada, dentro de una función, mantiene su valor en las diferentes llamadas a la función. El ejemplo típico es una función recursiva:

#include <stdio.h>
void my_function( int a );
int main() {
	my_function(0);
	printf("\n");
	my_function( 10 );
}
void my_function( int a ) {
	static int i;
	int b = 10;
	i += a;
	printf("| %d - %d |\t", i);
	i++;
	b++;
	if( i < 5 ) my_function( 0 );
}
Devuelve:

| 0 - 10 |	| 1 - 10 |	| 2 - 10 |	| 3 - 10 |	| 4 - 10 |
| 15 - 10 |
Nota: Las variables estáticas se inicializan en 0. Nota: Cada vez que se llama a una función sus variables no estáticas se inicializan de cero , incluso cuando se llama a esta función recursivamente ( se crea un espacio de memoria nuevo para guardar sus variables automáticas para cada invocación de la función ). Esto se ejemplifica claramente por el comportamiento de la variable b.

Algunas conclusiones

Fue muy interesante ver esto, sobre todo al especular sobre como desarrollar un programa a gran escala sobre C. Por ejemplo, se podría considerar a un archivo con sus funciones definidas y sus variables globales propias ( no accesibles para otros archivos ) como un proto-objeto donde sus variables globales son sus atributos y sus funciones son sus métodos. Ahora, como la única forma de acceder a una variable de otro archivo-proto-objeto es a través de extern, se vuelve hyper evidente lo complicado que se transforma desarrollar arquitecturas complejas lidiando con esto. Repentinamente el paradigma OOP se transforma en MARAVILLOSO después de pensar un poco en esto!!!!

Algunos agregados más

Existe la opción register al declarar una variable para guardarla directamente en los registros de la maquina si va a ser muy utilizada. Se puede declarar un array de la siguiente forma!!

int primos[] = { 2 , 3 , 5 , 7, 11 , 13 }

Referencias

The C Programming Language, Segunda Edición; Kernighan, Ritchie; Prentice Hall Hispanoamerica, 1991