La pregunta era simple C funciones, no c ++ static
métodos, como se aclara en los comentarios.
Entiendo qué es una static
variable, pero ¿qué es una static
funció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_matrix
se compila?
ACTUALIZACIÓN Solo para aclarar las cosas: sé que incluir .c
es malo, como muchos de ustedes señalaron. Solo lo hago para liberar espacio temporalmente main.c
hasta que tenga una mejor idea de cómo agrupar todas esas funciones en archivos .h
y .c
archivos apropiados . Solo una solución temporal y rápida.
fuente
Hay 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 se compila. En otras palabras, hacer una función estática limita su alcance. Puede pensar en una función estática como "privada" para su archivo * .c (aunque eso no es estrictamente correcto).
En C ++, "estático" también puede aplicarse a funciones miembro y miembros de datos de clases. Un miembro de datos estático también se denomina "variable de clase", mientras que un miembro de datos no estático 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ático. Por lo tanto, un miembro de datos estáticos es esencialmente una variable global, es decir, un miembro de una clase.
Las funciones de miembros no estáticos pueden acceder a todos los miembros de datos de la clase: estáticos y no estáticos. Las funciones de miembro estático 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.
fuente
Hay dos usos para la palabra clave static cuando se trata de funciones en C ++.
El primero es marcar la función como que tiene un enlace interno para que no pueda ser referenciada en otras unidades de traducción. Este uso está en desuso en C ++. Se prefieren espacios de nombres sin nombre para este uso.
El segundo uso es en el contexto de una clase. Si una clase tiene una función miembro estática, eso significa que la función es miembro de la clase (y tiene el acceso habitual a otros miembros), pero no necesita ser invocada a través de un objeto en particular. En otras palabras, dentro de esa función, no hay un puntero "este".
fuente
Ejemplo mínimo de alcance de múltiples archivos ejecutable
Aquí ilustramos cómo
static
afecta el alcance de las definiciones de funciones en múltiples archivos.C.A
C Principal
GitHub aguas arriba .
Compilar y ejecutar:
Salida:
Interpretación
sf
, una para cada archivof
Como de costumbre, cuanto menor sea el alcance, mejor, así que siempre declare funciones
static
si puede.En la programación en C, los archivos se usan a menudo para representar "clases", y las
static
funciones representan métodos "privados" de la clase.Un patrón común de C es pasar una
this
estructura como el primer argumento de "método", que es básicamente lo que C ++ hace bajo el capó.¿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
implicainternal linkage
:y 6.2.2 / 2 dice que se
internal linkage
comporta como en nuestro ejemplo:donde "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:
y desmonte la tabla de símbolos con:
la salida contiene:
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 :lo que lo convierte en una opción perfecta para representar
static
.Las funciones sin estática son
STB_GLOBAL
, y la especificación dice:que es coherente con los errores de enlace en múltiples definiciones no estáticas.
Si aumentamos la optimización con
-O3
, elsf
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 funciones estáticas en la tabla de símbolos cuando no hay optimización? ¿Se pueden usar para algo?Ver también
extern
es lo opuesto astatic
, y las funciones ya estánextern
por defecto: ¿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
fuente
void f() { puts("sf"); }
(es decir, dos definiciones def()
) provoca un comportamiento indefinido sin necesidad de diagnóstico. Es un problema de calidad de enlace ver realmente un mensaje de error.Lo siguiente es sobre las funciones simples de C: en una clase de C ++, el modificador 'estático' tiene otro significado.
Si solo tiene un archivo, este modificador no hace absolutamente 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 cada uno de esos archivos de objetos compilados (sample.o) se vinculan a un archivo ejecutable mediante el vinculador.
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 de objetos para esos dos módulos, pero el enlazador arrojará un error, porque encuentra dos funciones con el mismo nombre y no sabe cuál debería usar (incluso si no hay nada que vincular, porque no se usan en otro lugar sino en su propio archivo).Es por eso que hace que esta función, que solo se usa internamente, sea una función estática. En este caso, el compilador no crea la típica bandera "puede vincular esta cosa" para el enlazador, de modo que el enlazador no vea esta función y no genere un error.
fuente
Primero: generalmente es una mala idea incluir un
.cpp
archivo en otro archivo, ya que genera problemas como este :-) La forma normal es crear unidades de compilación separadas y agregar un archivo de encabezado para el archivo incluido.En segundo lugar:
C ++ tiene una terminología confusa aquí: no lo supe hasta que se señaló en los comentarios.
a)
static functions
- heredado de C, y de lo que estás hablando aquí. Fuera de cualquier clase. Una función estática significa que no es visible fuera de la unidad de compilación actual, por lo que en su caso a.obj tiene una copia y su otro código tiene una copia independiente. (Hinchando el ejecutable final con múltiples copias del código).b)
static member function
- lo que Orientación de Objeto llama un método estático . Vive dentro de una clase. Llama a esto con la clase en lugar de a través de una instancia de objeto.Estas dos definiciones diferentes de funciones estáticas son completamente diferentes. Ten cuidado, aquí hay dragones.
fuente
Las definiciones de funciones estáticas marcarán este símbolo como interno. Por lo tanto, no será visible para vincular desde el exterior, sino solo para funciones en la misma unidad de compilación, generalmente el mismo archivo.
fuente
Una función estática es aquella que se puede invocar en la clase misma, en oposición a una instancia de la clase.
Por ejemplo, un no estático sería:
Este método funciona en una instancia de la clase, no en la clase misma. Sin embargo, puede tener un método estático que funcione sin tener una instancia. Esto a veces se usa en el patrón Factory:
fuente
Nit menor: las funciones estáticas son visibles para una unidad de traducción, que para la mayoría de los casos prácticos es el archivo en el que se define la función. El error que está recibiendo se conoce comúnmente como violación de la Regla de una definición.
El estándar probablemente dice algo como:
Esa es la forma en C de ver las funciones estáticas. Sin embargo, esto está en desuso en C ++.
En C ++, además, puede declarar funciones miembro estáticas. Estas son principalmente metafunciones, es decir, no describen / modifican el comportamiento / estado de un objeto en particular, sino que actúan en toda la clase. Además, esto significa que no necesita crear un objeto para llamar a una función miembro estática. Además, esto también significa que solo obtiene acceso a variables miembro estáticas desde dicha función.
Agregaría al ejemplo de Parrot el patrón Singleton que se basa en este tipo de función miembro estática para obtener / usar un solo objeto durante la vida útil de un programa.
fuente
La respuesta a la función estática depende del idioma:
1) En lenguajes sin OOPS como C, significa que solo se puede acceder a la función dentro del archivo donde está definida.
2) En lenguajes con OOPS como C ++, significa que la función se puede invocar directamente en la clase sin crear una instancia de ella.
fuente
static
tiene un alcance de archivo, como en C.Dado que la función estática solo es visible en este archivo. En realidad, el compilador puede hacer alguna optimización por usted si declara "estático" a alguna función.
Aquí hay un ejemplo simple.
C Principal
Y compilar con
Verás que falló. Porque incluso no implementas la función ghost ().
Pero, ¿y si usamos el siguiente comando?
Es exitoso , y este programa puede ejecutarse normalmente.
¿Por qué? Hay 3 puntos clave.
Solo si estas 3 condiciones son todas verdaderas, puede pasar la compilación. Debido a esta declaración "estática", el compilador puede confirmar que nunca se llamará a test () en otro archivo. Su compilador puede eliminar test () al compilar. Como no necesitamos test (), no importa si ghost () está definido o implementado.
fuente
Empecemos desde el principio.
Todo se basa en una cosa llamada "vinculación":
Si una función se define sin un especificador de clase de almacenamiento, la función tiene un
extern
enlace por defecto:Eso significa que, si su programa contiene varias unidades de traducción / archivos fuente (
.c
o.cpp
), la función está visible en todas las unidades de traducción / archivos fuente que tiene su programa.Esto puede ser un problema en algunos casos. ¿Qué sucede si desea utilizar dos funciones diferentes (definiciones), pero con el mismo nombre de función en dos contextos diferentes (en realidad, el contexto del archivo).
En C y C ++, el
static
calificador de clase de almacenamiento aplicado a una función en el ámbito del archivo (no una función miembro estática de una clase en C ++ o una función dentro de otro bloque) ahora ayuda y significa que la función respectiva solo es visible dentro de la unidad de traducción / archivo fuente en el que se definió y no en las otras TLU / archivos.Por lo tanto, una
static
función solo tiene sentido si:Su programa contiene varias unidades de traducción / archivos fuente (
.c
o.cpp
).y
Desea limitar el alcance de una función al archivo, en el que se define la función específica.
Si no es así tanto de estos requisitos son correctos, no es necesario para envolver su cabeza en torno acerca de calificar como una función
static
.Notas al margen:
Como ya se mencionó, una
static
función no tiene absolutamente ninguna diferencia entre C y C ++, ya que esta es una característica que C ++ hereda de C.No importa que en la comunidad de C ++, haya un debate desgarrador sobre la depreciación de las funciones de calificación
static
en comparación con el uso de espacios de nombres sin nombre , primero inicializados por un párrafo fuera de lugar en el estándar C ++ 03, que declara el uso de funciones estáticas como obsoletas que pronto fueron revisadas por el comité y eliminadas en C ++ 11.Esto estaba sujeto a varias preguntas SO:
Espacios de nombres anónimos / sin nombre versus funciones estáticas
¿Superioridad del espacio de nombres sin nombre sobre el estático?
¿Por qué un espacio de nombres sin nombre es una alternativa "superior" a la estática?
Desuso de la palabra clave estática ... ¿no más?
De hecho, todavía no está en desuso por el estándar C ++. Por lo tanto, el uso de
static
funciones sigue siendo legítimo. Incluso si los espacios de nombres sin nombre tienen ventajas, la discusión sobre el uso o no de funciones estáticas en C ++ está sujeta a una sola mente (basada en opiniones) y con eso no es adecuado para este sitio web.fuente