Tiene usos tanto en C como en C ++.
Como adivinó, la staticparte limita su alcance a esa unidad de compilación . También proporciona inicialización estática. constsimplemente le dice al compilador que no permita que nadie lo modifique. Esta variable se coloca en el segmento de datos o bss, según la arquitectura, y podría estar en la memoria marcada como de solo lectura.
Así es como C trata estas variables (o cómo C ++ trata las variables de espacio de nombres). En C ++, un miembro marcado statices compartido por todas las instancias de una clase determinada. Si es privado o no, no afecta el hecho de que una variable sea compartida por varias instancias. Tener constallí le advertirá si algún código intenta modificarlo.
Si fuera estrictamente privado, cada instancia de la clase obtendría su propia versión (a pesar del optimizador).
Mucha gente dio la respuesta básica, pero nadie señaló que en C ++ el valor
constpredeterminado esstaticanamespacenivel (y algunos dieron información incorrecta). Consulte la sección 3.5.3 del estándar C ++ 98.Primero algunos antecedentes:
Unidad de traducción: un archivo de origen después de que el preprocesador (recursivamente) incluyó todos sus archivos de inclusión.
Enlace estático: un símbolo solo está disponible dentro de su unidad de traducción.
Enlace externo: un símbolo está disponible en otras unidades de traducción.
A
namespacenivelEsto incluye el espacio de nombres global, también conocido como variables globales .
A nivel de función
staticsignifica que el valor se mantiene entre llamadas a funciones.La semántica de las
staticvariables de función es similar a las variables globales en el sentido de que residen en el segmento de datos del programa (y no en la pila o en el montón). Consulte esta pregunta para obtener más detalles sobrestaticla vida útil de las variables.A
classnivelstaticsignifica que el valor se comparte entre todas las instancias de la clase yconstsignifica que no cambia.fuente
const int *foo(int x) {const int b=x;return &b};versusconst int *foo(int x) {static const int b=x;return &b};constimplicaciónstaticen este último.constdeclaración también implicastaticallí? Por ejemplo, si desechaconsty modifica el valor, ¿se modificarán todos los valores?constno implica estática a nivel de función, eso sería una pesadilla de concurrencia (¡const! = Expresión constante), todo a nivel de función es implícitaauto. Dado que esta pregunta también está etiquetada [c], debo mencionar que un nivel globalconst intestá implícitamenteexternen C. Sin embargo, las reglas que tiene aquí describen perfectamente C ++.staticindica que la variable es de duración estática (solo existe una copia, que dura desde el principio del programa hasta su final), y tiene un enlace interno / estático si no se especifica lo contrario (esto es anulado por la función enlace para variables estáticas locales, o enlace de clase para miembros estáticos). Las principales diferencias están en lo que esto implica en cada situación en la questatices válido.Esa línea de código puede aparecer en varios contextos diferentes y, aunque se comporta aproximadamente de la misma manera, existen pequeñas diferencias.
Alcance del espacio de nombres
'
i' será visible en cada unidad de traducción que incluya el encabezado. Sin embargo, a menos que realmente use la dirección del objeto (por ejemplo. '&i'), Estoy bastante seguro de que el compilador tratará 'i' simplemente como un tipo seguro0. Si dos unidades de traducción más toman el "&i", la dirección será diferente para cada unidad de traducción.'
i' tiene un enlace interno, por lo que no se puede hacer referencia a él desde fuera de esta unidad de traducción. Sin embargo, nuevamente, a menos que use su dirección, lo más probable es que se trate como un tipo seguro0.Una cosa que vale la pena señalar, es que la siguiente declaración:
es exactamente igual que
static const int i = 0. Una variable en un espacio de nombres declarada conconsty no declarada explícitamente conexternes implícitamente estática. Si piensa en esto, la intención del comité de C ++ era permitir que lasconstvariables se declaren en los archivos de encabezado sin necesitar siempre lastaticpalabra clave para evitar romper el ODR.Alcance de la clase
En el ejemplo anterior, el estándar especifica explícitamente que "
i" no necesita definirse si no se requiere su dirección. En otras palabras, si solo usa 'i' como un 0 con seguridad de tipos, el compilador no lo definirá. Una diferencia entre las versiones de clase y espacio de nombres es que la dirección de 'i' (si se usa en dos o más unidades de traducción) será la misma para el miembro de la clase. Donde se usa la dirección, debe tener una definición para ella:fuente
Es una optimización de espacio pequeño.
Cuando tu dices
No está definiendo una constante, sino creando una variable de solo lectura. El compilador es lo suficientemente inteligente como para usar 42 cada vez que ve foo, pero también le asignará espacio en el área de datos inicializados. Esto se hace porque, como se define, foo tiene un enlace externo. Otra unidad de compilación puede decir:
extern const int foo;
Para acceder a su valor. Esa no es una buena práctica, ya que esa unidad de compilación no tiene idea del valor de foo. Simplemente sabe que es un int const y tiene que recargar el valor de la memoria cada vez que se usa.
Ahora, al declarar que es estático:
El compilador puede hacer su optimización habitual, pero también puede decir "oye, nadie fuera de esta unidad de compilación puede ver foo y sé que siempre es 42, por lo que no es necesario asignarle espacio".
También debo señalar que en C ++, la forma preferida de evitar que los nombres escapen de la unidad de compilación actual es usar un espacio de nombres anónimo:
fuente
Falta un 'int'. Debería ser:
En C y C ++, declara una constante entera con un alcance de archivo local de valor 42.
¿Por qué 42? Si aún no lo sabe (y es difícil creer que no lo sabe), es una referencia a la Respuesta a la vida, el universo y todo .
fuente
En C ++,
es la forma preferida de definir y usar constantes. Es decir, use esto en lugar de
porque no subvierte el sistema de seguridad de tipos.
fuente
A todas las grandes respuestas, quiero agregar un pequeño detalle:
Si escribe complementos (por ejemplo, DLL o bibliotecas .so para ser cargadas por un sistema CAD), entonces static es un salvavidas que evita colisiones de nombres como esta:
Peor aún: el paso 3 puede comportarse de manera diferente según la optimización del compilador, el mecanismo de carga del complemento, etc.
Tuve este problema una vez con dos funciones auxiliares (mismo nombre, comportamiento diferente) en dos complementos. Declararlos estáticos resolvió el problema.
fuente
Según la especificación C99 / GNU99:
statices un especificador de clase de almacenamiento
los objetos del ámbito de nivel de archivo tienen un vínculo externo de forma predeterminada
constes un calificador de tipo (es parte del tipo)
palabra clave aplicada a la instancia izquierda inmediata, es decir
MyObj const * myVar;- puntero no calificado al tipo de objeto calificado constanteMyObj * const myVar;- puntero calificado const al tipo de objeto no calificadoUso más a la izquierda: se aplica al tipo de objeto, no a la variable
const MyObj * myVar;- puntero no calificado al tipo de objeto calificado constanteASÍ:
static NSString * const myVar;- puntero constante a cadena inmutable con enlace interno.La ausencia de la
staticpalabra clave hará que el nombre de la variable sea global y podría generar conflictos de nombres dentro de la aplicación.fuente
C ++ 17
inlinevariablesSi buscó en Google "C ++ const static", entonces es muy probable que lo que realmente quiera usar sean las variables en línea de C ++ 17 .
Esta impresionante característica de C ++ 17 nos permite:
constexpr: ¿Cómo declarar constexpr extern?main.cpp
notmain.hpp
notmain.cpp
Compila y ejecuta:
GitHub aguas arriba .
Consulte también: ¿Cómo funcionan las variables en línea?
Estándar C ++ en variables en línea
El estándar C ++ garantiza que las direcciones serán las mismas. Borrador estándar 10.1.6 de C ++ 17 N4659 "El especificador en línea":
cppreference https://en.cppreference.com/w/cpp/language/inline explica que si
staticno se proporciona, entonces tiene un enlace externo.Implementación de variables en línea de GCC
Podemos observar cómo se implementa con:
que contiene:
y
man nmdice sobreu:por lo que vemos que hay una extensión ELF dedicada para esto.
Pre-C ++ 17:
extern constAntes de C ++ 17, y en C, podemos lograr un efecto muy similar con an
extern const, que conducirá a que se utilice una única ubicación de memoria.Las desventajas
inlineson:constexprcon esta técnica, soloinlinepermite que: ¿Cómo declarar constexpr extern?main.cpp
notmain.cpp
notmain.hpp
GitHub aguas arriba .
Alternativas de encabezado previo a C ++ 17
Estos no son tan buenos como la
externsolución, pero funcionan y solo ocupan una única ubicación de memoria:Una
constexprfunción, porqueconstexprimplicainlineyinlinepermite (fuerza) que la definición aparezca en cada unidad de traducción :y apuesto a que cualquier compilador decente incluirá la llamada.
También puede usar una variable estática
constoconstexprcomo en:pero no puede hacer cosas como tomar su dirección, o de lo contrario se usa odr, vea también: Definición de miembros de datos estáticos constexpr
C
En C, la situación es la misma que en C ++ antes de C ++ 17, he subido un ejemplo en: ¿Qué significa "estático" en C?
La única diferencia es que en C ++,
constimplicastaticpara globales, pero no en C: C ++ semántica de `static const` vs` const`¿Alguna forma de alinearlo completamente?
TODO: ¿hay alguna forma de alinear completamente la variable, sin usar memoria en absoluto?
Muy parecido a lo que hace el preprocesador.
Esto requeriría de alguna manera:
Relacionado:
Probado en Ubuntu 18.10, GCC 8.2.0.
fuente
Sí, oculta una variable en un módulo de otros módulos. En C ++, lo uso cuando no quiero / necesito cambiar un archivo .h que desencadenará una reconstrucción innecesaria de otros archivos. Además, pongo la estática primero:
Además, dependiendo de su uso, el compilador ni siquiera le asignará almacenamiento y simplemente "alineará" el valor donde se usa. Sin la estática, el compilador no puede asumir que no se está usando en otro lugar y no puede estar en línea.
fuente
Esta es una constante global visible / accesible solo en el módulo de compilación (archivo .cpp). Por cierto, el uso de estática para este propósito está en desuso. Mejor use un espacio de nombres anónimo y una enumeración:
fuente
enumtiene en este contexto. ¿Cuidado para elaborar? Porenumslo general, estos solo se usan para evitar que el compilador asigne espacio para el valor (aunque los compiladores modernos no necesitan esteenumtruco para ello) y para evitar la creación de punteros al valor.Hacerlo privado aún significaría que aparece en el encabezado. Tiendo a usar "la forma más débil" que funciona. Vea este artículo clásico de Scott Meyers: http://www.ddj.com/cpp/184401197 (se trata de funciones, pero también se puede aplicar aquí).
fuente