he visto la palabra static
utilizado en diferentes lugares en código C; ¿Es esto como una función/clase estática en C# (donde la implementación se comparte entre objetos)?
¿Qué significa “estático” en C?
Sueño relajado
Hay un uso más que no se cubre aquí, y es como parte de una declaración de tipo de matriz como argumento de 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 en él. Para obtener más información, consulte mi pregunta aquí.
-
¿No pensé que C tenía argumentos de matriz? Linus Torvalds despotrica enojado sobre la gente que hace esto.
– suprjami
29 de septiembre de 2015 a las 11:02
-
@jamieb: C no tiene argumentos de matriz, pero esta sintaxis específica significa que la función espera
arg[0]
a través dearg[9]
tener valores (lo que también implica que la función no acepta un puntero nulo). 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 a la función nunca se le dé un puntero nulo (o si puede decirlo, una matriz con menos elementos que los especificados).– sueño relajado
29/09/2015 a las 21:16
-
@Qix: este fue un nuevo significado sobrecargado que se le dio a
static
en C99. Tiene más de una década y media, 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.– Siestas de Happy Green Kid
22 de diciembre de 2015 a las 16:42
-
@suprjami No estoy 100% seguro de lo que quieres decir con “argumentos de matriz”pero si te refieres
int arr[n];
entonces eso es un VLA (matriz de longitud variable), que se añadió en C99. ¿Es eso lo que querías decir?– RastaJedi
1 de mayo de 2016 a las 4:58
-
Quiere decir que no puedo pasar ningún char* a esta función, porque nadie sabe si se podría incrementar en 10… Dudo de tu respuesta, aunque es interesante.
– Nikolái Ehrhardt
20 de marzo a las 12:00
-
Entonces, ¿”función estática” y “función privada” significan lo mismo? De manera similar, ¿las “variables globales estáticas” y las “variables globales privadas” son lo mismo?
– usuario1599964
20 de enero de 2013 a las 8:56
-
Se trata de C. No hay privado/público en C.
– chris
14 de febrero de 2013 a las 7:34
-
@user1599964 aunque no hay
private
en C, su analogía es buena: la estática hace que las cosas sean “privadas” para un archivo determinado. Y los archivos en C a menudo se asignan a clases en C++.– Ciro Santilli Путлер Капут 六四事
23 de abril de 2015 a las 15:02
m sostenido
static
significa diferentes cosas 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 una global en el sentido de que solo se inicializa una vez y conserva su valor. En este ejemplo, cada vez que llama
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 quiere que su símbolo sea visible fuera del
.obj
generado por el archivo. p.ejstatic void foo() { ... }
Chris Tang
En programación C, static
es una palabra clave reservada que controla tanto la duración como la visibilidad. Si declaramos una variable como estática dentro de una función, solo será visible en toda esa función. En este uso, la vida útil de esta variable estática comenzará cuando una función llame 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, inicializará el count = 0
. Y mientras ejecutamos el counterFunction
destruirá la variable de conteo.
Ejemplo de ámbito de variable de varios archivos
Aquí ilustro cómo la estática afecta el alcance de las definiciones de funciones en varios archivos.
C.A
#include <stdio.h>
/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
https://stackoverflow.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://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
Producción:
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
uno para cada archivo - hay una sola variable compartida para
i
Como de costumbre, cuanto menor sea el alcance, mejor, así que siempre declare variables static
si puedes.
En la programación C, los archivos se utilizan a menudo para representar “clases” y static
las variables representan miembros estáticos privados de la clase.
Qué dicen las normas al respecto
Proyecto C99 N1256 6.7.1 “Especificadores de clase de almacenamiento” dice que static
es un “especificador de clase de almacenamiento”.
6.2.2/3 “Enlaces de identificadores” dice static
implica internal linkage
:
Si la declaración de un identificador de ámbito de archivo para un objeto o una función contiene el especificador de clase de almacenamiento estático, el identificador tiene un vínculo interno.
y 6.2.2/2 dice que internal linkage
se comporta como en nuestro ejemplo:
En el conjunto de unidades de traducción y bibliotecas que constituye 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 lo implementa GCC para ELF (Linux)?
Con el STB_LOCAL
vinculante.
Si compilamos:
int i = 0;
static int si = 0;
y desmontar 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
por lo que la unión es la única diferencia significativa entre ellos. Value
es solo su compensación en el .bss
sección, 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. 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.
lo cual es coherente con los errores de enlace en múltiples definiciones no estáticas.
Si aumentamos la optimización con -O3
la si
El símbolo se elimina por completo de la tabla de símbolos: de todos modos no se puede utilizar desde el exterior. TODO ¿Por qué mantener las variables estáticas en la tabla de símbolos cuando no hay optimización? ¿Se pueden usar para cualquier cosa? Tal vez para la depuración.
Ver también
- análogo para
static
funciones: https://stackoverflow.com/a/30319812/895245 - comparar
static
conextern
que hace “lo contrario”: ¿Cómo uso extern para compartir variables entre archivos fuente?
Espacios de nombres anónimos de 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 sin nombre/anónimos frente a funciones estáticas
Relacionada: Estático (palabra clave) @ Wikipedia
– Palec
06/02/2015 a las 13:31
¿Cuál es la razón para eliminar “en un programa C” del final del título, @Lundin? Es un poco redundante en presencia de la etiqueta c, pero me permite ver la categorización más rápidamente, sin inspeccionar las etiquetas. Esta redundancia es muy cómoda cuando llego a la pregunta desde una dirección que también puede contener preguntas sobre otros idiomas, por ejemplo, estática o búsqueda de Google.
– Palec
22 mayo 2017 a las 14:55
@Lundin Prefiero mantener “C” en el título, porque SO solo agrega una etiqueta al título (¿la más común?). ¿Qué pasa si algún día la “sintaxis” llega a más preguntas que C (ya que es una cosa de lenguaje cruzado)? Prefiero usar el comportamiento explícito 🙂 Editar: ah, pero hay una meta pregunta que dice lo contrario: meta.stackexchange.com/questions/19190/…
– Ciro Santilli Путлер Капут 六四事
17 de junio de 2017 a las 10:46
Esta es una explicación que encontré en Quora. ¡Definitivamente vale la pena leerlo!
– nalzok
27 de agosto de 2017 a las 13:45
La duración del almacenamiento de estática es hasta que finaliza el programa, en lugar de hasta que finaliza el alcance.
– usuario12211554
14 mayo 2020 a las 18:20