variable - ¿Qué significa "estático" en C?
volatile c (18)
- Una variable estática dentro de una función mantiene su valor entre invocaciones.
- Una variable global estática o una función se "ve" solo en el archivo que se declara en
(1) es el tema más extraño si eres un novato, así que aquí tienes un ejemplo:
#include <stdio.h>
void foo()
{
int a = 10;
static int sa = 10;
a += 5;
sa += 5;
printf("a = %d, sa = %d/n", a, sa);
}
int main()
{
int i;
for (i = 0; i < 10; ++i)
foo();
}
Esto imprime:
a = 15, sa = 15
a = 15, sa = 20
a = 15, sa = 25
a = 15, sa = 30
a = 15, sa = 35
a = 15, sa = 40
a = 15, sa = 45
a = 15, sa = 50
a = 15, sa = 55
a = 15, sa = 60
Esto es útil para los casos en que una función necesita mantener cierto estado entre las invocaciones y no desea utilizar variables globales. Tenga cuidado, sin embargo, esta característica debe usarse con moderación: hace que su código no sea seguro para subprocesos y más difícil de entender.
(2) Se utiliza ampliamente como una función de "control de acceso". Si tiene un archivo .c que implementa alguna funcionalidad, generalmente expone solo algunas funciones "públicas" a los usuarios. El resto de sus funciones deben hacerse static
, para que el usuario no pueda acceder a ellas. Esta es la encapsulación, una buena práctica.
Citando Wikipedia :
En el lenguaje de programación C, la estática se utiliza con variables y funciones globales para establecer su alcance en el archivo que lo contiene. En las variables locales, estática se utiliza para almacenar la variable en la memoria asignada estáticamente en lugar de la memoria asignada automáticamente. Si bien el lenguaje no dicta la implementación de ninguno de los tipos de memoria, la memoria asignada estáticamente se reserva normalmente en el segmento de datos del programa en el momento de la compilación, mientras que la memoria asignada automáticamente se implementa normalmente como una pila de llamadas transitorias.
Vea here y here para más detalles.
Y para responder a tu segunda pregunta, no es como en C #.
Sin embargo, en C ++, static
también se usa para definir atributos de clase (compartidos entre todos los objetos de la misma clase) y métodos. En C no hay clases, por lo que esta característica es irrelevante.
He visto la palabra static
utilizada en diferentes lugares en el código C; ¿Es esto como una función / clase estática en C # (donde la implementación se comparte entre objetos)?
De Wikipedia:
En el lenguaje de programación C, la estática se utiliza con variables y funciones globales para establecer su alcance en el archivo que lo contiene. En las variables locales, estática se utiliza para almacenar la variable en la memoria asignada estáticamente en lugar de la memoria asignada automáticamente. Si bien el lenguaje no dicta la implementación de ninguno de los tipos de memoria, la memoria asignada estáticamente se reserva normalmente en el segmento de datos del programa en el momento de la compilación, mientras que la memoria asignada automáticamente se implementa normalmente como una pila de llamadas transitorias.
Depende:
int foo()
{
static int x;
return ++x;
}
La función devolvería 1, 2, 3, etc. --- la variable no está en la pila.
C.A:
static int foo()
{
}
Significa que esta función tiene alcance solo en este archivo. Entonces, ac y bc pueden tener diferentes foo()
s, y foo no está expuesto a objetos compartidos. Entonces, si definiste foo en ac, no podrías acceder desde bc
o desde ningún otro lugar.
En la mayoría de las bibliotecas de C, todas las funciones "privadas" son estáticas y la mayoría de las "públicas" no lo son.
En C, estática tiene dos significados, dependiendo del alcance de su uso. En el ámbito global, cuando un objeto se declara a nivel de archivo, significa que ese objeto solo es visible dentro de ese archivo.
En cualquier otro ámbito, declara un objeto que conservará su valor entre los diferentes momentos en que se ingresa el ámbito particular. Por ejemplo, si se borra un int dentro de un procedimiento:
void procedure(void)
{
static int i = 0;
i++;
}
el valor de ''i'' se inicializa a cero en la primera llamada al procedimiento, y el valor se retiene cada vez que se llama al procedimiento. si se imprimiera ''i'', se emitiría una secuencia de 0, 1, 2, 3, ...
Es importante tener en cuenta que las variables estáticas en las funciones se inicializan en la primera entrada a esa función y persisten incluso después de que su llamada haya finalizado; en el caso de las funciones recursivas, la variable estática se inicializa solo una vez y persiste también en todas las llamadas recursivas e incluso después de que la llamada de la función haya finalizado.
Si la variable se ha creado fuera de una función, significa que el programador solo puede usar la variable en el archivo fuente, la variable ha sido declarada.
Hay 2 casos:
(1) Variables locales declaradas static
: asignadas en el segmento de datos en lugar de la pila. Su valor se conserva cuando vuelve a llamar a la función.
(2) Variables globales o funciones declaradas static
: Unidad de compilación externa invisible (es decir, son símbolos locales en la tabla de símbolos durante el enlace).
Hay un uso más no cubierto aquí, y eso es como parte de una declaración de tipo de matriz como un argumento a una función:
int someFunction(char arg[static 10])
{
...
}
En este contexto, esto especifica que los argumentos pasados a esta función deben ser una matriz de tipo char
con al menos 10 elementos. Para más información vea mi pregunta here .
La gente sigue diciendo que ''estático'' en C tiene dos significados. Ofrezco una forma alternativa de verlo que le da un significado único:
- La aplicación de ''estática'' a un elemento obliga a ese elemento a tener dos propiedades: (a) No es visible fuera del alcance actual; (b) Es persistente.
La razón por la que parece tener dos significados es que, en C, cada elemento al que se puede aplicar ''estática'' ya tiene una de estas dos propiedades , por lo que parece que ese uso en particular solo involucra a la otra.
Por ejemplo, considere variables. Las variables declaradas fuera de las funciones ya tienen persistencia (en el segmento de datos), por lo que la aplicación de ''estática'' solo puede hacer que no sean visibles fuera del alcance actual (unidad de compilación). Por el contrario, las variables declaradas dentro de las funciones ya no tienen visibilidad fuera del alcance actual (función), por lo que la aplicación de ''estática'' solo puede hacerlas persistentes.
Aplicar ''estática'' a las funciones es como aplicarla a variables globales: el código es necesariamente persistente (al menos dentro del lenguaje), por lo que solo se puede modificar la visibilidad.
NOTA: Estos comentarios solo se aplican a C. En C ++, la aplicación de ''estática'' a los métodos de clase realmente le da a la palabra clave un significado diferente. Del mismo modo para la extensión de argumento-matriz C99.
Las variables estáticas en C tienen la vida útil del programa.
Si se definen en una función, tienen un alcance local, es decir, solo se puede acceder a ellas dentro de esas funciones. El valor de las variables estáticas se conserva entre las llamadas a funciones.
Por ejemplo:
void function()
{
static int var = 1;
var++;
printf("%d", var);
}
int main()
{
function(); // Call 1
function(); // Call 2
}
En el programa anterior, var
se almacena en el segmento de datos. Su vida es todo el programa de C
Después de la llamada a la función 1, var
convierte en 2. Después de la llamada a la función 2, var
convierte en 3.
El valor de var
no se destruye entre las llamadas de funciones.
Si var
tuviera entre una variable no estática y una local, se almacenaría en el segmento de pila en el programa C. Dado que el marco de pila de la función se destruye después de que la función retorna, el valor de var
también se destruye.
Las variables estáticas inicializadas se almacenan en el segmento de datos del programa C, mientras que las no inicializadas se almacenan en el segmento BSS.
Otra información sobre la estática: si una variable es global y estática, tiene la vida útil del programa C, pero tiene el alcance del archivo. Es visible solo en ese archivo.
Para probar esto:
archivo1.c
static int x;
int main()
{
printf("Accessing in same file%d", x):
}
archivo2.c
extern int x;
func()
{
printf("accessing in different file %d",x); // Not allowed, x has the file scope of file1.c
}
run gcc -c file1.c
gcc -c file2.c
Ahora intenta vincularlos usando:
gcc -o output file1.o file2.o
Daría un error al enlazador ya que x tiene el alcance del archivo de file1.c y el enlazador no podría resolver la referencia a la variable x utilizada en file2.c.
Referencias:
Odio responder una pregunta anterior, pero no creo que nadie haya mencionado cómo K&R lo explica en la sección A4.1 de "El lenguaje de programación C".
En resumen, la palabra estática se usa con dos significados:
- La estática es una de las dos clases de almacenamiento (la otra es automática). Un objeto estático mantiene su valor entre invocaciones. Los objetos declarados fuera de todos los bloques son siempre estáticos y no pueden hacerse automáticos.
- Pero, cuando la palabra clave
static
(con gran énfasis en que se use en el código como una palabra clave) se usa con una declaración, le da a ese objeto un enlace interno, de modo que solo se puede usar dentro de esa unidad de traducción. Pero si la palabra clave se usa en una función, cambia la clase de almacenamiento del objeto (el objeto solo sería visible dentro de esa función de todos modos). Lo opuesto a estática es la palabra claveextern
, que proporciona un enlace externo al objeto.
Peter Van Der Linden da estos dos significados en "Programación Experto C":
- Dentro de una función, conserva su valor entre llamadas.
- A nivel de función, visible solo en este archivo.
Respuesta corta ... depende.
Las variables locales definidas estáticamente no pierden su valor entre las llamadas de función. En otras palabras, son variables globales, pero con alcance a la función local en la que están definidas.
Las variables globales estáticas no son visibles fuera del archivo C en el que están definidas.
Las funciones estáticas no son visibles fuera del archivo C en el que están definidas.
Si declara esto en un archivo mytest.c:
static int my_variable;
Entonces esta variable solo se puede ver desde este archivo. La variable no se puede exportar a ningún otro lugar.
Si declara dentro de una función, el valor de la variable mantendrá su valor cada vez que se llame a la función.
Una función estática no se puede exportar desde fuera del archivo. Entonces, en un archivo * .c, está ocultando las funciones y las variables si las declara estáticas.
Si declara una variable en una función estática, su valor no se almacenará en la pila de llamadas de función y seguirá estando disponible cuando vuelva a llamar a la función.
Si declara una variable global estática, su alcance se restringirá dentro del archivo en el que la declaró. Esto es ligeramente más seguro que un global regular que puede leerse y modificarse en todo el programa.
También hay que tener en cuenta que la static
se puede utilizar de 4 maneras diferentes.
to create permanent storage for local variables in a function.
to specify internal linkage.
to declare member functions that act like non-member functions.
to create a single copy of a data member.
Un valor variable estático persiste entre las diferentes llamadas de función y su alcance está limitado al bloque local, una variable estática siempre se inicializa con el valor 0
Una variable estática es una variable especial que puede usar en una función, guarda los datos entre llamadas y no los elimina entre llamadas. Por ejemplo:
void func(){
static int count; // If you don''t declare its value, the value automatically initializes to zero
printf("%d, ", count);
count++;
}
void main(){
while(true){
func();
}
}
La salida:
0, 1, 2, 3, 4, 5, ...
static
significa diferentes cosas en diferentes contextos.
Puede declarar una variable estática en una función de C. Esta variable solo es visible en la función, sin embargo, se comporta como un global, ya que solo se inicializa una vez y conserva su valor. En este ejemplo, cada vez que llame a
foo()
se imprimirá un número creciente. La variable estática se inicializa una sola vez.void foo () { static int i = 0; printf("%d", i); i++ }
Otro uso de la estática es cuando implementas una función o variable global en un archivo .c pero no quieres que su símbolo sea visible fuera del
.obj
generado por el archivo. p.ejstatic void foo() { ... }
Ejemplo de alcance variable de archivos múltiples
Aquí ilustro cómo la estática afecta el alcance de las definiciones de funciones en múltiples archivos.
C.A
#include <stdio.h>
/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
https://.com/questions/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*int i = 0;*/
/* Works in GCC as an extension: https://.com/a/3692486/895245 */
/*int i;*/
/* OK: extern. Will use the one in main. */
extern int i;
/* OK: only visible to this file. */
static int si = 0;
void a() {
i++;
si++;
puts("a()");
printf("i = %d/n", i);
printf("si = %d/n", si);
puts("");
}
C Principal
#include <stdio.h>
int i = 0;
static int si = 0;
void a();
void m() {
i++;
si++;
puts("m()");
printf("i = %d/n", i);
printf("si = %d/n", si);
puts("");
}
int main() {
m();
m();
a();
a();
return 0;
}
Compilar
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
Salida
m()
i = 1
si = 1
m()
i = 2
si = 2
a()
i = 3
si = 1
a()
i = 4
si = 2
Interpretación
- hay dos variables separadas para
si
, una para cada archivo - hay una sola variable compartida para
i
Como de costumbre, cuanto más pequeño sea el alcance, mejor, así que siempre declare las variables static
si puede.
En la programación en C, los archivos se usan a menudo para representar "clases", y las variables static
representan miembros estáticos privados de la clase.
Lo que dicen los estándares al respecto
C99 N1256 draft 6.7.1 "Especificadores de clase de almacenamiento" dice que static
es un "especificador de clase de almacenamiento".
6.2.2 / 3 "Los enlaces de los identificadores" dicen que la static
implica internal linkage
:
Si la declaración de un identificador de alcance de archivo para un objeto o una función contiene el estático especificador de la clase de almacenamiento, el identificador tiene un enlace interno.
y 6.2.2 / 2 dice que internal linkage
comporta como en nuestro ejemplo:
En el conjunto de unidades de traducción y bibliotecas que constituyen un programa completo, cada declaración de un identificador particular con enlace externo denota el mismo objeto o función. Dentro de una unidad de traducción, cada declaración de un identificador con enlace interno denota el mismo objeto o función.
donde "unidad de traducción es un archivo fuente después del preprocesamiento.
¿Cómo GCC lo implementa para ELF (Linux)?
Con el enlace STB_LOCAL
.
Si compilamos:
int i = 0;
static int si = 0;
y desmonte la tabla de símbolos con:
readelf -s main.o
la salida contiene:
Num: Value Size Type Bind Vis Ndx Name
5: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 si
10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 i
Así que la unión es la única diferencia significativa entre ellos. Value
es solo su compensación en la sección .bss
, por lo que esperamos que difiera.
STB_LOCAL
está documentado en la especificación ELF en http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :
STB_LOCAL Los símbolos locales no son visibles fuera del archivo de objeto que contiene su definición. Pueden existir símbolos locales del mismo nombre en varios archivos sin interferir entre sí
lo que la convierte en una opción perfecta para representar static
.
Las variables sin estática son STB_GLOBAL
, y la especificación dice:
Cuando el editor de enlaces combina varios archivos de objetos reubicables, no permite múltiples definiciones de símbolos STB_GLOBAL con el mismo nombre.
que es coherente con los errores de enlace en múltiples definiciones no estáticas.
Si aumentamos la optimización con -O3
, el símbolo si
se elimina por completo de la tabla de símbolos: no se puede utilizar desde el exterior de todos modos. TODO ¿por qué mantener las variables estáticas en la tabla de símbolos cuando no hay optimización? ¿Pueden ser utilizados para cualquier cosa? Tal vez para la depuración.
Ver también
- análogo a las funciones
static
: https://.com/a/30319812/895245 - compare
static
conextern
, que hace "lo contrario": ¿Cómo uso extern para compartir variables entre archivos de origen?
Inténtalo tú mismo
Ejemplo en github para que juegues.