¿Qué significa “estático” en C?

8 minutos de lectura

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)?

  • 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

avatar de usuario
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 de arg[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

avatar de usuario
m sostenido

static significa diferentes cosas en diferentes contextos.

  1. 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++
    }
    
  2. 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.ej

    static void foo() { ... }
    

avatar de usuario
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;
}

GitHub ascendente.

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 siuno 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_GLOBALy 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 -O3la 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 con externque 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

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad