Tiene usos tanto en C como en C ++.
Como adivinó, la static
parte limita su alcance a esa unidad de compilación . También proporciona inicialización estática. const
simplemente 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 static
es 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 const
allí 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
const
predeterminado esstatic
anamespace
nivel (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
namespace
nivelEsto incluye el espacio de nombres global, también conocido como variables globales .
A nivel de función
static
significa que el valor se mantiene entre llamadas a funciones.La semántica de las
static
variables 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 sobrestatic
la vida útil de las variables.A
class
nivelstatic
significa que el valor se comparte entre todas las instancias de la clase yconst
significa 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};
const
implicaciónstatic
en este último.const
declaración también implicastatic
allí? Por ejemplo, si desechaconst
y modifica el valor, ¿se modificarán todos los valores?const
no 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 int
está implícitamenteextern
en C. Sin embargo, las reglas que tiene aquí describen perfectamente C ++.static
indica 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 questatic
es 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 conconst
y no declarada explícitamente conextern
es implícitamente estática. Si piensa en esto, la intención del comité de C ++ era permitir que lasconst
variables se declaren en los archivos de encabezado sin necesitar siempre lastatic
palabra 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:
static
es un especificador de clase de almacenamiento
los objetos del ámbito de nivel de archivo tienen un vínculo externo de forma predeterminada
const
es 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
static
palabra 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
inline
variablesSi 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
static
no 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 nm
dice sobreu
:por lo que vemos que hay una extensión ELF dedicada para esto.
Pre-C ++ 17:
extern const
Antes 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
inline
son:constexpr
con esta técnica, soloinline
permite 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
extern
solución, pero funcionan y solo ocupan una única ubicación de memoria:Una
constexpr
función, porqueconstexpr
implicainline
yinline
permite (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
const
oconstexpr
como 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 ++,
const
implicastatic
para 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
enum
tiene en este contexto. ¿Cuidado para elaborar? Porenums
lo general, estos solo se usan para evitar que el compilador asigne espacio para el valor (aunque los compiladores modernos no necesitan esteenum
truco 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