Pregunta ¿Qué significa "estático" en C?


He visto la palabra static utilizado 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)?


854
2018-02-21 06:47


origen


Respuestas:


  1. Una variable estática dentro de una función mantiene su valor entre invocaciones.
  2. Una variable global estática o una función se "ve" solo en el archivo en el que está declarado

(1) es el tema más extranjero 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 casos donde una función necesita mantener algún estado entre invocaciones, y no desea usar variables globales. Sin embargo, tenga en cuenta que esta característica se debe usar con moderación: hace que su código no sea seguro para subprocesos y más difícil de entender.

(2) Se usa 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 deberían estar hechas static, para que el usuario no pueda acceder a ellos. Esto es encapsulación, una buena práctica.

Citando Wikipedia:

En el lenguaje de programación C, static   se usa con variables globales y   funciones para establecer su alcance a la   que contiene el archivo. En variables locales,   static se usa para almacenar la variable   en la memoria estáticamente asignada   en lugar de la asignación automática   memoria. Si bien el lenguaje no   dictar la implementación de cualquiera   tipo de memoria, asignada estáticamente   la memoria está generalmente reservada en datos   segmento del programa en compilación   tiempo, mientras que el   memoria asignada es normalmente   implementado como una pila de llamadas transitorias.

Ver aquí y aquí para más detalles.

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.


1221
2018-02-21 06:51



Hay un uso más no cubierto aquí, y eso 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 en él. Para más información vea mi pregunta aquí.


188
2018-05-01 07:13



Respuesta corta ... depende.

  1. Las variables locales estáticas definidas no pierden su valor entre llamadas a funciones. En otras palabras, son variables globales, pero tienen un alcance para la función local en la que están definidas.

  2. Las variables globales estáticas no son visibles fuera del archivo C en el que están definidas.

  3. Las funciones estáticas no son visibles fuera del archivo C en el que están definidas.


140
2018-02-21 06:56



Ejemplo de alcance de variable multi-archivo

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;
}

Compilacion:

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, uno para cada archivo
  • hay una sola variable compartida para i

Como de costumbre, cuanto menor sea el alcance, mejor, por lo tanto, siempre declare las variables staticsi puedes.

En la programación en C, los archivos se usan a menudo para representar "clases", y static las variables representan miembros estáticos privados de la clase.

Qué dicen los estándares al respecto

Borrador 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 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 internal linkage se 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 un enlace externo denota el mismo objeto o función. Dentro de una unidad de traducción, cada declaración de un identificador con un 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 el STB_LOCAL Unión.

Si compilamos:

int i = 0;
static int si = 0;

y desmontar la tabla de símbolos con:

readelf -s main.o

el resultado 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 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 objeto que contiene su definición. Los símbolos locales del mismo nombre pueden existir en múltiples archivos sin interferir entre ellos

que lo hace una elección perfecta para representar static.

Las variables sin estática son STB_GLOBALy la especificación dice:

Cuando el editor de enlaces combina varios archivos de objeto 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 El símbolo se elimina por completo de la tabla de símbolos: no se puede usar desde afuera de ninguna manera. TODO ¿por qué mantener 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

Inténtalo tú mismo

Ejemplo en github para que juegues.


45
2018-01-15 13:41



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 a.c y b.c pueden tener diferente foo()s, y foo no está expuesto a objetos compartidos. Entonces, si definiste foo en a.c, no podrías acceder desde b.c o desde cualquier 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.


32
2018-02-21 06:57



La gente sigue diciendo que "estática" en C tiene dos significados. Ofrezco una forma alternativa de verlo que le da un significado único:

  • Aplicar 'estático' 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 como si ese uso particular solo involucrara 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 aplicar 'estático' 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 tienen visibilidad fuera del alcance actual (función), por lo que la aplicación de '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 modificar la visibilidad.

NOTA: Estos comentarios solo se aplican a C. En C ++, la aplicación de métodos "estáticos" a la clase realmente está dando a la palabra clave un significado diferente. Del mismo modo para la extensión de argumento de matriz C99.


18
2018-04-27 13:47



static significa cosas diferentes en diferentes contextos.

  1. Puede declarar una variable estática en una función C. Esta variable solo es visible en la función, pero se comporta como un global en el sentido de que solo se inicializa una vez y conserva su valor. En este ejemplo, cada vez que llamas 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++
    }
    
  2. Otro uso de estática 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() { ... }
    

12
2018-02-21 06:55