¿Qué es una función "estática" en C?

Resuelto Slava V asked hace 15 años • 11 respuestas

La pregunta era sobre simpleCfunciones, noc++ staticmétodos, como se aclara en los comentarios.

Entiendo qué statices una variable, pero ¿qué es una staticfunción?

¿Y por qué si declaro una función, digamos void print_matrix, digamos a.c(SIN a.h) e incluyo "a.c", obtengo "print_matrix@@....) already defined in a.obj", PERO si la declaro como static void print_matrixentonces se compila?

ACTUALIZACIÓN Sólo para aclarar las cosas: sé que incluir .ces malo, como muchos de ustedes señalaron. Solo lo hago para liberar espacio temporalmente main.chasta que tenga una mejor idea de cómo agrupar todas esas funciones en archivos .hy adecuados .c. Sólo una solución temporal y rápida.

Slava V avatar Feb 18 '09 01:02 Slava V
Aceptado

staticLas funciones son funciones que solo son visibles para otras funciones en el mismo archivo (más precisamente, la misma unidad de traducción ).

EDITAR : Para aquellos que pensaron que el autor de las preguntas se refería a un 'método de clase': como la pregunta está etiquetada, Cse refiere a una función C simple y antigua. Para los métodos de clase (C++/Java/...), staticsignifica que este método se puede llamar en la clase misma, no es necesaria una instancia de esa clase.

Johannes Weiss avatar Feb 17 '2009 18:02 Johannes Weiss

Existe una gran diferencia entre las funciones estáticas en C y las funciones miembro estáticas en C++. En C, una función estática no es visible fuera de su unidad de traducción, que es el archivo objeto en el que está compilada. En otras palabras, hacer que una función sea estática limita su alcance. Puede pensar que una función estática es "privada" de su archivo *.c (aunque eso no es estrictamente correcto).

En C++, "estático" también se puede aplicar a funciones miembro y miembros de datos de clases. Un miembro de datos estáticos también se denomina "variable de clase", mientras que un miembro de datos no estáticos es una "variable de instancia". Esta es la terminología de Smalltalk. Esto significa que solo hay una copia de un miembro de datos estáticos compartida por todos los objetos de una clase, mientras que cada objeto tiene su propia copia de un miembro de datos no estáticos. Entonces, un miembro de datos estáticos es esencialmente una variable global, es decir, un miembro de una clase.

Las funciones miembro no estáticas pueden acceder a todos los miembros de datos de la clase: estáticos y no estáticos. Las funciones de miembros estáticos solo pueden operar en los miembros de datos estáticos.

Una forma de pensar en esto es que en C++ los miembros de datos estáticos y las funciones de miembros estáticos no pertenecen a ningún objeto, sino a toda la clase.

Dima avatar Feb 17 '2009 18:02 Dima

Ejemplo de alcance mínimo ejecutable de varios archivos

Aquí ilustro cómo staticafecta 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
 */
/*void f() { puts("a f"); }*/

/* OK: only declared, not defined. Will use the one in main. */
void f(void);

/* OK: only visible to this file. */
static void sf() { puts("a sf"); }

void a() {
    f();
    sf();
}

C Principal

#include <stdio.h>

void a(void);        

void f() { puts("main f"); }

static void sf() { puts("main sf"); }

void m() {
    f();
    sf();
}

int main() {
    m();
    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
./main

Producción:

main f
main sf
main f
a sf

Interpretación

  • Hay dos funciones separadas sf, una para cada archivo.
  • hay una única función compartidaf

Como es habitual, cuanto menor sea el alcance, mejor, así que siempre declara funciones staticsi puedes.

En la programación C, los archivos se utilizan a menudo para representar "clases" y staticlas funciones representan métodos "privados" de la clase.

Un patrón común de C es pasar una thisestructura como primer argumento de "método", que es básicamente lo que hace C++ bajo el capó.

¿Qué dicen las normas al respecto?

C99 N1256 borrador 6.7.1 "Especificadores de clase de almacenamiento" dice que statices un "especificador de clase de almacenamiento".

6.2.2/3 "Vínculos de identificadores" dice staticimplica 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 linkagese 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 la STB_LOCALencuadernación.

Si compilamos:

int f() { return 0; }
static int sf() { return 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: 000000000000000b    11 FUNC    LOCAL  DEFAULT    1 sf
  9: 0000000000000000    11 FUNC    GLOBAL DEFAULT    1 f

entonces la unión es la única diferencia significativa entre ellos. Valuees solo su desplazamiento en la .bsssección, por lo que esperamos que difiera.

STB_LOCALestá 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 con el mismo nombre pueden existir en varios archivos sin interferir entre sí.

lo que lo convierte en una elección perfecta para representar static.

Las funciones 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 -O3, el sfsímbolo se elimina por completo de la tabla de símbolos: de todos modos no se puede usar desde afuera. TODO ¿Por qué mantener funciones estáticas en la tabla de símbolos cuando no hay optimización? ¿Se pueden usar para cualquier cosa?

Ver también

  • Lo mismo para las variables: https://stackoverflow.com/a/14339047/895245
  • externes lo opuesto a staticy las funciones ya están externpredeterminadas: ¿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 tipos: espacios de nombres anónimos/sin nombre versus funciones estáticas

Lo siguiente trata sobre funciones simples de C: en una clase de C++ el modificador 'estático' tiene otro significado.

Si tiene un solo archivo, este modificador no hace ninguna diferencia. La diferencia viene en proyectos más grandes con múltiples archivos:

En C, cada "módulo" (una combinación de sample.c y sample.h) se compila de forma independiente y luego el vinculador vincula cada uno de esos archivos objeto compilados (sample.o) a un archivo ejecutable.

Digamos que tiene varios archivos que incluye en su archivo principal y dos de ellos tienen una función que solo se usa internamente por conveniencia llamada add(int a, b): el compilador crearía fácilmente archivos objeto para esos dos módulos, pero el vinculador arrojará un error, porque encuentra dos funciones con el mismo nombre y no sabe cuál debe usar (incluso si no hay nada que vincular, porque no se usan en ningún otro lugar excepto en su propio archivo).

Es por eso que haces de esta función, que solo se usa internamente, una función estática. En este caso, el compilador no crea el típico indicador "puedes vincular esto" para el vinculador, de modo que el vinculador no ve esta función y no genera un error.

dersimn avatar Apr 25 '2013 22:04 dersimn

Las definiciones de funciones estáticas marcarán este símbolo como interno. Por lo tanto, no será visible para enlaces desde fuera, sino sólo para funciones en la misma unidad de compilación, normalmente el mismo archivo.

raimue avatar Feb 17 '2009 18:02 raimue