La palabra clave 'static' en C tiene dos significados fundamentalmente diferentes.
Alcance limitante
En este contexto, 'static' se empareja con 'extern' para controlar el alcance de una variable o nombre de función. Estático hace que el nombre de la variable o función esté disponible solo dentro de una sola unidad de compilación y solo disponible para el código que existe después de la declaración / definición dentro del texto de la unidad de compilación.
Esta limitación en sí misma solo significa algo si y solo si tiene más de una unidad de compilación en su proyecto. Si solo tiene una unidad de compilación, entonces todavía hace las cosas, pero esos efectos son en su mayoría inútiles (a menos que le guste excavar en archivos de objetos para leer lo que generó el compilador).
Como se señaló, esta palabra clave en este contexto se empareja con la palabra clave 'extern', que hace lo contrario, al hacer que la variable o el nombre de la función se puedan vincular con el mismo nombre que se encuentra en otras unidades de compilación. Por lo tanto, puede considerar que 'static' requiere que la variable o el nombre se encuentren dentro de la unidad de compilación actual, mientras que 'extern' permite el enlace de unidades de compilación cruzada.
Vida estática
La duración estática significa que la variable existe a lo largo de la duración del programa (por mucho tiempo que sea). Cuando usa 'estática' para declarar / definir una variable dentro de una función, significa que la variable se crea en algún momento antes de su primer uso ( lo que significa, cada vez que lo he experimentado, que la variable se crea antes de que comience main () y no se destruye después. Ni siquiera cuando la ejecución de la función se completa y vuelve a su llamador. Y al igual que las variables de vida útil estáticas declaradas fuera de las funciones, se inicializan en el mismo momento, antes de que main () comience, a un cero semántico (si no se proporciona ninguna inicialización) oa un valor explícito específico, si se proporciona.
Esto es diferente de las variables de función de tipo 'automático', que se crean nuevas (o, como si fueran nuevas) cada vez que se ingresa la función y luego se destruyen (o, como si se destruyeron) cuando la función sale.
A diferencia del impacto de aplicar 'estática' en una definición de variable fuera de una función, que afecta directamente su alcance, declarar una variable de función (dentro de un cuerpo de función, obviamente) como 'estática' no tiene impacto en su alcance. El alcance está determinado por el hecho de que se definió dentro de un cuerpo de función. Las variables de duración estática definidas dentro de las funciones tienen el mismo alcance que otras variables 'automáticas' definidas dentro de los cuerpos de las funciones: alcance de funciones.
Resumen
Entonces, la palabra clave 'estática' tiene contextos diferentes con lo que equivale a "significados muy diferentes". La razón por la que se usó de dos maneras, como esta, fue para evitar usar otra palabra clave. (Hubo una larga discusión al respecto). Se consideró que los programadores podían tolerar el uso y el valor de evitar otra palabra clave más en el lenguaje era más importante (que los argumentos de lo contrario).
(Todas las variables declaradas fuera de las funciones tienen una vida útil estática y no necesitan la palabra clave 'static' para que eso sea cierto. Por lo tanto, este tipo de palabra clave se liberó para usarse allí para significar algo completamente diferente: 'visible solo en una sola compilación unidad. 'Es un truco, de algún tipo.)
Nota específica
estático volátil sin signo char PORTB @ 0x06;
La palabra 'estática' aquí debe interpretarse en el sentido de que el vinculador no intentará hacer coincidir múltiples ocurrencias de PORTB que se pueden encontrar en más de una unidad de compilación (suponiendo que su código tenga más de una).
Utiliza una sintaxis especial (no portátil) para especificar la "ubicación" (o el valor numérico de la etiqueta, que generalmente es una dirección) de PORTB. Entonces, el enlazador recibe la dirección y no necesita encontrar una. Si tuviera dos unidades de compilación usando esta línea, cada una terminaría apuntando al mismo lugar, de todos modos. Entonces no hay necesidad de etiquetarlo como 'externo', aquí.
Si hubieran usado 'externo' podría plantear un problema. El enlazador entonces podría ver (e intentaría hacer coincidir) múltiples referencias a PORTB encontradas en múltiples compilaciones. Si todos ellos especifican una dirección como esta, y las direcciones NO son las mismas por alguna razón [¿error?], Entonces ¿qué se supone que debe hacer? ¿Quejar? ¿O? (Técnicamente, con 'externo' la regla general sería que solo UNA unidad de compilación especificaría el valor y las demás no deberían).
Es más fácil etiquetarlo como 'estático', evitando que el enlazador se preocupe por los conflictos, y simplemente culpe por cualquier error en las direcciones que no coinciden con quien cambió la dirección a algo que no debería ser.
De cualquier manera, la variable se trata como si tuviera una 'vida útil estática'. (Y 'volátil').
Una declaración no es una definición , pero todas las definiciones son declaraciones
En C, una definición crea un objeto. También lo declara. Pero una declaración generalmente no (vea la nota de viñeta a continuación) crea un objeto.
Las siguientes son definiciones y declaraciones:
static int a;
static int a = 7;
extern int b = 5;
extern int f() { return 10; }
Las siguientes no son definiciones, sino solo declaraciones:
extern int b;
extern int f();
Tenga en cuenta que las declaraciones no crean un objeto real. Solo declaran los detalles al respecto, que el compilador puede usar para ayudar a generar el código correcto y proporcionar mensajes de advertencia y error, según corresponda.
Arriba, digo "por lo general", aconsejado. En algunos casos, una declaración puede crear un objeto y, por lo tanto, el vinculador la promueve a una definición (nunca el compilador). Por lo tanto, incluso en este raro caso, el compilador C todavía piensa que la declaración es solo una declaración. Es la fase de enlace que hace las promociones necesarias de alguna declaración. Tenga esto en cuenta cuidadosamente.
En los ejemplos anteriores, si resulta que solo hay declaraciones para un "extern int b;" en todas las unidades de compilación vinculadas, el vinculador tiene la responsabilidad de crear una definición. Tenga en cuenta que este es un evento de tiempo de enlace. El compilador es completamente inconsciente, durante la compilación. Solo se puede determinar en el momento del enlace, si se promueve una declaración de este tipo.
El compilador es consciente de que "static int a;" no puede ser promovido por el enlazador durante el enlace, por lo que este hecho es una definición en tiempo de compilación .