variable examples example c function static

examples - static function php



¿Qué es una función "estática"? (10)

A continuación, se trata de funciones C simples: 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, posteriormente, cada uno de esos archivos de objetos compilados (sample.o) se vinculan entre sí 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á fácilmente archivos de objeto para esos dos módulos, pero el vinculador generará un error, ya que 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 ningún otro lugar sino en su propio archivo).

Por esta razón, esta función, que solo se utiliza de forma interna, es una función estática. En este caso, el compilador no crea el típico "se puede vincular esta cosa" -flag para el vinculador, por lo que el vinculador no ve esta función y no generará un error.

La pregunta era acerca de las funciones c simples, no static métodos static c ++ , como se aclara en los comentarios.

Ok, entiendo qué es una variable static , pero ¿qué es una función static ?

¿Y por qué es que si declaro una función, digamos void print_matrix , en digamos ac (SIN ah ) e "print_matrix@@....) already defined in a.obj" "ac" - Obtengo "print_matrix@@....) already defined in a.obj" , PERO Si lo declaro como static void print_matrix entonces compila?

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


Hay dos usos para la palabra clave estática cuando se trata de funciones en C ++.

La primera es marcar la función como que tiene un enlace interno para que no se pueda hacer referencia en otras unidades de traducción. Este uso está en desuso en C ++. Se prefieren los espacios de nombres sin nombre para este uso.

// inside some .cpp file: static void foo(); // old "C" way of having internal linkage // C++ way: namespace { void this_function_has_internal_linkage() { // ... } }

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 un miembro de la clase (y tiene el acceso habitual a otros miembros), pero no es necesario invocarla a través de un objeto en particular. En otras palabras, dentro de esa función, no hay un puntero "este".


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 que una función estática es "privada" a su archivo * .c (aunque eso no es estrictamente correcto).

En C ++, "estática" también se puede aplicar a funciones de miembros 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 compartidos 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, que es un miembro de una clase.

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

Una forma de pensar sobre 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.


La respuesta a la función estática depende del idioma:

1) En idiomas sin OOPS como C, significa que la función es accesible solo dentro del archivo donde está definido.

2) En lenguajes con OOPS como C ++, significa que la función se puede llamar directamente en la clase sin crear una instancia de ella.


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


Las funciones estáticas son visibles para una unidad de traducción, que en 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:

"Cada programa debe contener exactamente una definición de cada función u objeto no en línea que se utiliza en ese programa; no se requiere diagnóstico".

Esa es la forma C de mirar las funciones estáticas. Esto está en desuso en C ++ sin embargo.

En C ++, además, puede declarar las funciones miembro estáticas. En su mayoría son metafunciones, es decir, no describen / modifican el comportamiento / estado de un objeto en particular, sino que actúan sobre la clase en sí. Además, esto significa que no es necesario crear un objeto para llamar a una función miembro estática. Además, esto también significa que solo tiene acceso a las variables miembro estáticas desde dentro de dicha función.

Agregaré 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 toda la vida útil de un programa.


Primero: en general, es una mala idea incluir un archivo .cpp en otro archivo. Esto conduce a 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 sabía hasta que lo señalaban en los comentarios.

a) static functions - heredadas de C, y de lo que estás hablando aquí. Fuera de cualquier clase. Una función estática significa que no está 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 la Orientación del objeto denomina método estático. Vive dentro de una clase. Se llama a esto con la clase en lugar de hacerlo a través de una instancia de objeto.

Estas dos definiciones de funciones estáticas diferentes son completamente diferentes. Ten cuidado, aquí hay dragones.


Una función estática es una que se puede llamar en la clase en sí, a diferencia de una instancia de la clase.

Por ejemplo un no estático sería:

Person* tom = new Person(); tom->setName("Tom");

Este método funciona en una instancia de la clase, no en la clase en sí. Sin embargo, puede tener un método estático que puede funcionar sin tener una instancia. Esto se usa a veces en el patrón de Fábrica:

Person* tom = Person::createNewPerson();


static funciones static 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 significaba un ''método de clase'': como la pregunta está etiquetada C , significa una función C antigua y simple. Para los métodos de clase (C ++ / Java / ...), static significa que este método se puede llamar en la propia clase, no es necesaria ninguna instancia de esa clase.


Ejemplo de alcance de varios archivos mínimo ejecutable

Aquí ilustro cómo la static afecta el alcance de las definiciones de funciones en múltiples archivos.

C.A

#include <stdio.h> /* Undefined behavior: already defined in main. * Binutils 2.24 gives an error and refuses to link. * https://.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; }

Compilar

gcc -c a.c -o a.o gcc -c main.c -o main.o gcc -o main main.o a.o

Salida

main f main sf main f a sf

Interpretación

  • hay dos funciones separadas sf , una para cada archivo
  • hay una sola función compartida f

Como de costumbre, cuanto menor sea el alcance, mejor, así que siempre declare las funciones static si puede.

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

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

Lo que dicen los estándares 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 "Los enlaces de los identificadores" dicen que la static implica internal linkage :

Si la declaración de un identificador de alcance de archivo para un objeto o una función contiene el estático especificador de la clase de almacenamiento, el identificador tiene un enlace interno.

y 6.2.2 / 2 dice que internal linkage 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 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 de origen después del preprocesamiento.

¿Cómo GCC lo implementa para ELF (Linux)?

Con el enlace STB_LOCAL .

Si compilamos:

int f() { return 0; } static int sf() { return 0; }

y desmonte 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

Así que la unión es la única diferencia significativa entre ellos. Value es solo su compensación en la sección .bss , 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. Pueden existir símbolos locales del mismo nombre en varios archivos sin interferir entre sí

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

Las funciones 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.

que es coherente con los errores de enlace en múltiples definiciones no estáticas.

Si aumentamos la optimización con -O3 , el símbolo sf se elimina por completo de la tabla de símbolos: no se puede utilizar desde el exterior de todos modos. TODO ¿por qué mantener las funciones estáticas en la tabla de símbolos cuando no hay optimización? ¿Pueden ser utilizados para cualquier cosa?

Ver también

Inténtalo tú mismo

Ejemplo en GitHub para que juegues.