He visto la palabra static
usada 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)?
He visto la palabra static
usada 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)?
Respuestas:
(1) es el tema más extraño si eres un novato, así que aquí hay 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 invocaciones y no desea utilizar variables globales. Sin embargo, tenga cuidado, esta característica debe usarse con moderación: hace que su código no sea seguro para subprocesos y sea 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 unas pocas funciones "públicas" a los usuarios. El resto de sus funciones deben realizarse static
para que el usuario no pueda acceder a ellas. Esto es encapsulación, una buena práctica.
Citando Wikipedia :
En el lenguaje de programación C, static se usa con variables y funciones globales para establecer su alcance en el archivo contenedor. En las variables locales, static se usa 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 generalmente en el segmento de datos del programa en tiempo de compilación, mientras que la memoria asignada automáticamente se implementa normalmente como una pila de llamadas transitorias.
Y para responder a su segunda pregunta, no es como en C #.
En C ++, sin embargo, 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.
.c
y un montón de archivos de encabezado, pero el demonio siempre está en lo que no es típico.
Hay un uso más no cubierto aquí, y es como parte de una declaración de tipo de matriz como argumento para 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 aquí .
arg[0]
a través de a arg[9]
tener valores (que también implica que la función no acepta un puntero null). Los compiladores podrían utilizar esta información de alguna manera para la optimización, y los analizadores estáticos pueden utilizar esta información para garantizar que la función nunca reciba un puntero nulo (o si puede decirlo, una matriz con menos elementos de los especificados).
static
en C99. Tiene más de una década y media de antigüedad, pero no todos los escritores de compiladores han adoptado todas las características de C99, por lo que C99 en su conjunto sigue siendo desconocido.
int arr[n];
, entonces es un VLA (matriz de longitud variable) , que se agregó en C99. ¿Es eso lo que querías decir?
Respuesta corta ... depende.
Las variables locales definidas estáticamente no pierden su valor entre las llamadas a funciones. En otras palabras, son variables globales, pero abarcan la función local en la que se definen.
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.
private
en C, su analogía es buena: la estática hace que las cosas sean "privadas" para un archivo dado. Y los archivos en C a menudo se asignan a clases en C ++.
Ejemplo de alcance variable de múltiples archivos
Aquí ilustramos 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.
/programming/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*int i = 0;*/
/* Works in GCC as an extension: https://stackoverflow.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 y ejecutar:
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
si
, una para cada archivoi
Como de costumbre, cuanto menor sea el alcance, mejor, así que siempre declare variables static
si puede.
En la programación en C, los archivos se usan a menudo para representar "clases", y las static
variables representan miembros privados estáticos de la clase.
¿Qué dicen las normas 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 "Vínculos de identificadores" dice static
implica internal linkage
:
Si la declaración de un identificador de alcance de archivo para un objeto o una función contiene el especificador de clase de almacenamiento estático, el identificador tiene un enlace interno.
y 6.2.2 / 2 dice que se 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 "la unidad de traducción es un archivo fuente después del preprocesamiento.
¿Cómo lo implementa GCC para ELF (Linux)?
Con la STB_LOCAL
encuadernación.
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
entonces el enlace es la única diferencia significativa entre ellos. Value
es solo su desplazamiento en la .bss
sección, por lo que esperamos que sea diferente.
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. Los símbolos locales del mismo nombre pueden existir en varios archivos sin interferir entre sí
lo que lo 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 si
símbolo se elimina por completo de la tabla de símbolos: de todos modos, no se puede usar desde afuera. TODO ¿por qué mantener las variables estáticas en la tabla de símbolos cuando no hay optimización? ¿Se pueden usar para algo? Tal vez para la depuración.
Ver también
static
funciones: https://stackoverflow.com/a/30319812/895245static
con extern
, lo que hace "lo contrario": ¿Cómo uso extern para compartir variables entre archivos fuente?Espacios de nombres anónimos C ++
En C ++, es posible que desee utilizar espacios de nombres anónimos en lugar de estáticos, lo que logra un efecto similar, pero oculta aún más las definiciones de tipo: espacios de nombres anónimos / sin nombre frente a funciones estáticas
Depende:
int foo()
{
static int x;
return ++x;
}
La función devolvería 1, 2, 3, etc. --- la variable no está en la pila.
static int foo()
{
}
Significa que esta función solo tiene alcance 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 a él b.c
desde ningún otro lugar.
En la mayoría de las bibliotecas C, todas las funciones "privadas" son estáticas y la mayoría de las "públicas" no lo son.
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 razón por la que parece tener dos significados es que, en C, cada elemento al que se puede aplicar 'estático' ya tiene una de estas dos propiedades , por lo que parece que ese uso particular solo involucra al otro.
Por ejemplo, considere las variables. Las variables declaradas fuera de las funciones ya tienen persistencia (en el segmento de datos), por lo que la aplicación '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 'estática' solo puede hacerlas persistentes.
Aplicar 'estático' a las funciones es como aplicarlo a variables globales: el código es necesariamente persistente (al menos dentro del lenguaje), por lo que solo se puede alterar la visibilidad.
NOTA: Estos comentarios solo se aplican a C. En C ++, la aplicación 'estática' a los métodos de clase realmente le da a la palabra clave un significado diferente. De manera similar para la extensión de argumento de matriz C99.
static
da enlace interno a un identificador.
De Wikipedia:
En el lenguaje de programación C, static se usa con variables y funciones globales para establecer su alcance en el archivo contenedor. En las variables locales, static se usa 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 típicamente en el segmento de datos del programa en tiempo de compilación, mientras que la memoria asignada automáticamente se implementa normalmente como una pila de llamadas transitorias.
static
significa cosas diferentes en diferentes contextos.
Puede declarar una variable estática en una función C. Esta variable solo es visible en la función, sin embargo, se comporta como global, ya que solo se inicializa una vez y conserva su valor. En este ejemplo, cada vez que llame foo()
, imprimirá un número creciente. La variable estática se inicializa solo una vez.
void foo ()
{
static int i = 0;
printf("%d", i); i++
}
Otro uso de static es cuando implementa una función o variable global en un archivo .c pero no desea que su símbolo sea visible fuera del .obj
generado por el archivo. p.ej
static void foo() { ... }
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 estará restringido dentro del archivo en el que lo declaró. Esto es un poco más seguro que un global regular que se puede leer y modificar en todo el programa.
Odio responder una vieja pregunta, 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:
static
palabra clave (gran énfasis en que se use en el código como palabra clave) se usa con una declaración, le da ese enlace interno al objeto, por lo 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ático es la extern
palabra clave, que proporciona un enlace externo a un objeto.Peter Van Der Linden da estos dos significados en "Programación experta C":
register
un especificador de clase de almacenamiento (C99 6.7.1 Especificadores de clase de almacenamiento). Y es más que una simple sugerencia, por ejemplo, no puede aplicar la dirección del operador &
en un objeto con clase de almacenamiento, register
independientemente de si el compilador asigna un registro o no.
En C, estático 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 retendrá su valor entre las diferentes veces que se ingresa el ámbito particular. Por ejemplo, si un int está delimitado 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', generarí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 en 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 durante 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 en el que se ha declarado la variable.
Si declaras esto en un mytest.c
archivo:
static int my_variable;
Entonces esta variable solo se puede ver desde este archivo. La variable no se puede exportar a ningún otro lado.
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 *.c
archivo, está ocultando las funciones y las variables si las declara estáticas.
Las variables estáticas en C tienen la vida útil del programa.
Si se definen en una función, tienen 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 útil es todo el programa C.
Después de la llamada a la función 1, se var
convierte en 2. Después de la llamada a la función 2, se var
convierte en 3.
El valor de var
no se destruye entre llamadas a funciones.
Si se var
tuviera entre una variable local y no estática, se almacenaría en el segmento de pila en el programa C. Dado que el marco de la pila de la función se destruye después de que la función regresa, 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 estática: si una variable es global y estática, tiene el tiempo de vida del programa C, pero tiene alcance de archivo. Solo es visible en ese archivo.
Para probar esto:
static int x;
int main()
{
printf("Accessing in same file%d", x):
}
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 de enlazador ya que x tiene el alcance de archivo de file1.c y el enlazador no podría resolver la referencia a la variable x utilizada en file2.c.
Referencias
static int var = 1;
cambia el valor a uno cada vez
Una variable estática es una variable especial que puede usar en una función y 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, ...
printf("%d, ", count); count++;
con `printf ("% d ", count ++) (no es que importe: P).
Hay 2 casos:
(1) Variables locales declaradas static
: asignadas en el segmento de datos en lugar de la pila. Su valor se retiene cuando vuelve a llamar a la función.
(2) Variables o funciones globales declaradas static
: Invisible fuera de la unidad de compilación (es decir, son símbolos locales en la tabla de símbolos durante el enlace).
¡Las variables estáticas tienen la propiedad de preservar su valor incluso después de estar fuera de su alcance! Por lo tanto, las variables estáticas conservan su valor anterior en su alcance anterior y no se inicializan nuevamente en el nuevo alcance.
Mire esto, por ejemplo: una variable int estática permanece en la memoria mientras se ejecuta el programa. Una variable normal o automática se destruye cuando finaliza una llamada a la función donde se declaró la variable.
#include<stdio.h>
int fun()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
Esto generará: 1 2
Como 1 permanece en la memoria como se declaró estático
Las variables estáticas (como las variables globales) se inicializan como 0 si no se inicializan explícitamente. Por ejemplo, en el siguiente programa, el valor de x se imprime como 0, mientras que el valor de y es algo basura. Vea esto para más detalles.
#include <stdio.h>
int main()
{
static int x;
int y;
printf("%d \n %d", x, y);
}
Esto dará como resultado: 0 [some_garbage_value]
¡Estos son los principales que encontré que no se explicaron anteriormente para un novato!
En la programación en C, static
es una palabra clave reservada que controla tanto la vida útil como la visibilidad. Si declaramos una variable como estática dentro de una función, entonces solo será visible a través de esa función. En este uso, la vida útil de esta variable estática comenzará cuando se llame a una función y se destruirá después de la ejecución de esa función. puedes ver el siguiente ejemplo:
#include<stdio.h>
int counterFunction()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("First Counter Output = %d\n", counterFunction());
printf("Second Counter Output = %d ", counterFunction());
return 0;
}
El programa anterior nos dará esta salida:
First Counter Output = 1
Second Counter Output = 1
Porque tan pronto como llamemos a la función, se inicializará count = 0
. Y mientras ejecutamos counterFunction
, destruirá la variable de conteo.