Al refactorizar algunos #defines
, encontré declaraciones similares a las siguientes en un archivo de encabezado de C ++:
static const unsigned int VAL = 42;
const unsigned int ANOTHER_VAL = 37;
La pregunta es, ¿qué diferencia, si la hay, hará la estática? Tenga en cuenta que la inclusión múltiple de los encabezados no es posible debido al #ifndef HEADER
#define HEADER
#endif
truco clásico (si eso importa).
¿Significa estática que solo VAL
se crea una copia de , en caso de que el encabezado esté incluido en más de un archivo fuente?
Respuestas:
Esto
static
significa que habrá una copia deVAL
creado para cada archivo fuente en el que se incluye. Pero también significa que múltiples inclusiones no darán como resultado múltiples definicionesVAL
que colisionarán en el momento del enlace. En C, sin elstatic
, necesitaría asegurarse de que solo un archivoVAL
fuente esté definido mientras que los otros archivos fuente lo declararonextern
. Por lo general, uno haría esto definiéndolo (posiblemente con un inicializador) en un archivo fuente y colocando laextern
declaración en un archivo de encabezado.static
las variables a nivel global solo son visibles en su propio archivo fuente, ya sea que hayan llegado a través de una inclusión o que estén en el archivo principal.Nota del editor: en C ++, los
const
objetos que no tienen ni las palabras clavestatic
niextern
en su declaración son implícitamentestatic
.fuente
Las etiquetas
static
yextern
en las variables de ámbito de archivo determinan si son accesibles en otras unidades de traducción (es decir, otros.c
o.cpp
archivos).static
da a la variable vinculación interna, ocultándola de otras unidades de traducción. Sin embargo, las variables con vinculación interna se pueden definir en varias unidades de traducción.extern
le da a la variable enlace externo, haciéndola visible para otras unidades de traducción. Normalmente, esto significa que la variable solo debe definirse en una unidad de traducción.El valor predeterminado (cuando no especifica
static
oextern
) es una de esas áreas en las que C y C ++ difieren.En C, las variables de ámbito de archivo son
extern
(enlace externo) de forma predeterminada. Si está utilizando C,VAL
esstatic
yANOTHER_VAL
esextern
.En C ++, las variables de ámbito de archivo son
static
(enlace interno) de forma predeterminada si lo sonconst
, yextern
de forma predeterminada si no lo son. Si está usando C ++, ambosVAL
y loANOTHER_VAL
sonstatic
.De un borrador de la especificación C :
De un borrador de la especificación C ++ :
fuente
La estática significará que obtendrá una copia por archivo, pero a diferencia de otros que han dicho que es perfectamente legal hacerlo. Puede probar esto fácilmente con una pequeña muestra de código:
test.h:
test1.cpp:
test2.cpp:
Ejecutar esto le da esta salida:
fuente
TEST
fueraconst
, si LTO podría optimizarlo en una sola ubicación de memoria. Pero-O3 -flto
de GCC 8.1 no lo hizo.const
las variables en C ++ tienen vínculos internos. Entonces, usarstatic
no tiene ningún efecto.ah
one.cpp
two.cpp
Si se tratara de un programa en C, obtendría un error de 'definición múltiple' para
i
(debido a un enlace externo).fuente
static
tiene el efecto de señalar claramente la intención y la conciencia de lo que se está codificando, lo cual nunca es malo. Para mí, esto es como incluirvirtual
cuando se anula: no tenemos que hacerlo, pero las cosas se ven mucho más intuitivas y coherentes con otras declaraciones cuando lo hacemos.La declaración estática en este nivel de código significa que la variabel solo es visible en la unidad de compilación actual. Esto significa que solo el código dentro de ese módulo verá esa variable.
si tiene un archivo de encabezado que declara una variable estática y ese encabezado está incluido en varios archivos C / CPP, entonces esa variable será "local" para esos módulos. Habrá N copias de esa variable para los N lugares en los que se incluye el encabezado. No están relacionados entre sí en absoluto. Cualquier código dentro de cualquiera de esos archivos fuente solo hará referencia a la variable declarada dentro de ese módulo.
En este caso particular, la palabra clave 'estática' no parece proporcionar ningún beneficio. Puede que me esté perdiendo algo, pero parece que no importa: nunca antes había visto algo así.
En cuanto a la inserción, en este caso la variable probablemente esté integrada, pero eso es solo porque se declara const. El compilador podría ser más probable que las variables de módulo estático en línea, pero eso es depende de la situación y el código que está siendo recopilada. No hay garantía de que el compilador incorpore 'estática'.
fuente
const
, elstatic
está implícito y, por lo tanto, es opcional. El corolario es que no hay susceptibilidad a múltiples errores de definición como afirmó Mike F.El libro C (gratuito en línea) tiene un capítulo sobre vinculación, que explica el significado de 'estático' con más detalle (aunque la respuesta correcta ya se da en otros comentarios): http://publications.gbdirect.co.uk/c_book /chapter4/linkage.html
fuente
Para responder a la pregunta, "¿la estática significa que solo se crea una copia de VAL, en caso de que el encabezado esté incluido en más de un archivo fuente?" ...
NO . VAL siempre se definirá por separado en cada archivo que incluya el encabezado.
Los estándares para C y C ++ causan una diferencia en este caso.
Tenga en cuenta que los enlazadores modernos pueden quejarse de ANOTHER_VAL si el encabezado se incluye en archivos diferentes (el mismo nombre global se define dos veces), y definitivamente se quejarían si se inicializara ANOTHER_VAL con un valor diferente en otro archivo
También debe tener en cuenta el hecho de que ambas variables se designan const. Idealmente, el compilador siempre elegiría alinear estas variables y no incluir ningún almacenamiento para ellas. Hay una gran cantidad de razones por las que se puede asignar almacenamiento. Los que puedo pensar ...
fuente
Suponiendo que estas declaraciones tienen un alcance global (es decir, no son variables miembro), entonces:
estático significa "enlace interno". En este caso, dado que se declara const, el compilador puede optimizarlo / alinearlo. Si omite la constante , el compilador debe asignar almacenamiento en cada unidad de compilación.
Al omitir estático, el enlace es externo de forma predeterminada. Una vez más, la const ness lo ha salvado : el compilador puede optimizar el uso en línea. Si elimina la constante , obtendrá un error de símbolos definidos múltiples en el momento del enlace.
fuente
No puede declarar una variable estática sin definirla también (esto se debe a que los modificadores de clase de almacenamiento static y extern son mutuamente excluyentes). Se puede definir una variable estática en un archivo de encabezado, pero esto haría que cada archivo de origen que incluye el archivo de encabezado tenga su propia copia privada de la variable, que probablemente no sea lo que se pretendía.
fuente
Las variables const son estáticas por defecto en C ++, pero extern C. Entonces, si usa C ++, no tiene sentido qué construcción usar.
(7.11.6 C ++ 2003 y Apexndix C tiene ejemplos)
Ejemplo en comparar fuentes de compilación / enlace como programa C y C ++:
fuente
static
. Señala la intención / conciencia de lo que está haciendo el programador y mantiene la paridad con otros tipos de declaración (y, fwiw, C) que carecen de lo implícitostatic
. Es como incluirvirtual
y últimamenteoverride
en declaraciones de funciones primordiales: no es necesario, pero es mucho más autodocumentado y, en el caso de este último, propicio para el análisis estático.const
solo en una variable en un encabezado cong++ (GCC) 7.2.1 20170915 (Red Hat 7.2.1-2)
. Resultó en aproximadamente 150 símbolos definidos multiplicados (uno para cada unidad de traducción se incluyó el encabezado). Creo que necesitamos, ya seastatic
,inline
o un / espacio de nombres sin nombre en el anonimato para evitar la vinculación externa.const int
dentro del alcance del espacio de nombres y en el espacio de nombres global. Y está compilado y sigue la regla "Los objetos declarados const y no explícitamente declarados extern tienen enlace interno". ".... Tal vez en el proyecto, por alguna razón, este encabezado se incluye en las fuentes compiladas de C, donde las reglas son completamente diferentes.Static evita que otra unidad de compilación extermine esa variable para que el compilador pueda simplemente "alinear" el valor de la variable donde se usa y no crear almacenamiento de memoria para ella.
En su segundo ejemplo, el compilador no puede asumir que algún otro archivo fuente no lo externará, por lo que en realidad debe almacenar ese valor en la memoria en algún lugar.
fuente
Static evita que el compilador agregue varias instancias. Esto se vuelve menos importante con la protección #ifndef, pero asumiendo que el encabezado está incluido en dos bibliotecas separadas y la aplicación está vinculada, se incluirían dos instancias.
fuente
static
"menos importante". e incluso con ambos, puede terminar con múltiples definiciones vinculadas internamente, lo que probablemente no sea el previsto.