c++ - usar - variable static java
¿Se puede declarar una variable tanto estática como externa? (4)
C ++:
7.1.1 Especificadores de clase de almacenamiento [dcl.stc]
7) Un nombre declarado en un ámbito de espacio de nombres sin un especificador de clase de almacenamiento tiene un enlace externo a menos que tenga un enlace interno debido a una declaración anterior y siempre que no se declare const. Los objetos declarados const y no externamente declarados externamente tienen vinculación interna.
Entonces, el primero intenta dar primero el enlace externo y luego el interno.
La segunda le da un enlace interno primero, y la segunda línea no intenta darle un enlace externo porque se declaró previamente como interno.
8) Los vínculos implícitos en las declaraciones sucesivas de una entidad dada deberán coincidir. Es decir, dentro de un alcance dado, cada declaración que declare el mismo nombre de variable o la misma sobrecarga del nombre de una función implicará el mismo enlace. Sin embargo, cada función en un conjunto dado de funciones sobrecargadas puede tener un enlace diferente.
[Ejemplo:
[...]
static int b; // b has internal linkage
extern int b; // b still has internal linkage
[...]
extern int d; // d has external linkage
static int d; // error: inconsistent linkage
[...]
¿Por qué lo siguiente no compila?
...
extern int i;
static int i;
...
Pero si invierte el orden, se compila bien.
...
static int i;
extern int i;
...
¿Que esta pasando aqui?
En Microsoft Visual Studio, ambas versiones se compilan perfectamente. En Gnu C ++ obtienes un error.
No estoy seguro de qué compilador es "correcto". De cualquier manera, tener ambas líneas no tiene mucho sentido.
extern int i
significa que el entero i
está definido en algún otro módulo (archivo de objeto o biblioteca). Esta es una declaración. El compilador no asignará el almacenamiento i
en este objeto, pero reconocerá la variable cuando la esté utilizando en otro lugar del programa.
int i
le dice al compilador que asigne almacenamiento para i
. Esta es una definición. Si otros archivos C ++ (o C) tienen int i
, el vinculador se quejará, ese int i se define dos veces.
static int i
es similar al anterior, con la funcionalidad adicional de que i
es local. No se puede acceder a él desde otro módulo, incluso si declaran extern int i
. La gente está usando la palabra clave static (en este contexto) para mantener i localize.
Por lo tanto, tener i
declarado como definido en otro lugar, Y definido como estático dentro del módulo parece un error. Visual Studio no dice nada al respecto, y g ++ solo lo hace en un orden específico, pero de cualquier forma no debería tener ambas líneas en el mismo código fuente.
Esto se da específicamente como un ejemplo en el estándar de C ++ cuando se analizan las complejidades de declarar un enlace externo o interno. Está en la sección 7.1.1.7, que tiene este ejercicio:
static int b ; // b has internal linkage
extern int b ; // b still has internal linkage
extern int d ; // d has external linkage
static int d ; // error: inconsistent linkage
La Sección 3.5.6 discute cómo debería comportarse extern
en este caso.
Lo que sucede es esto: static int i
(en este caso) es una definición, donde la static
indica que i
enlace interno. Cuando se produce extern
después de la static
el compilador ve que el símbolo ya existe y acepta que ya tiene vínculos internos y continúa. Por eso compila tu segundo ejemplo.
El extern
por otro lado, es una declaración, declara implícitamente que el símbolo tiene un enlace externo pero en realidad no crea nada. Como no hay i
en su primer ejemplo, el compilador registra que i
tiene un enlace externo, pero cuando llega a su static
, encuentra la declaración incompatible de que tiene un enlace interno y da un error.
En otras palabras, es porque las declaraciones son ''más suaves'' que las definiciones. Por ejemplo, podría declarar lo mismo varias veces sin error, pero solo puede definirlo una vez.
Si esto es igual en C, no lo sé (pero la respuesta de netcoder a continuación nos informa que el estándar C contiene el mismo requisito).
Para C, citando el estándar, en C11 6.2.2: Enlace de identificadores :
3) Si la declaración de un identificador de alcance de archivo para un objeto o una función contiene el
static
especificador de la clase de almacenamiento, el identificador tiene un enlace interno.4) Para un identificador declarado con el especificador de la clase de almacenamiento
extern
en un ámbito en el que es visible una declaración previa de ese identificador , si la declaración anterior especifica un enlace interno o externo, el enlace del identificador en la declaración posterior es el mismo que El enlace especificado en la declaración anterior . Si no hay una declaración previa visible, o si la declaración anterior no especifica ningún enlace, entonces el identificador tiene un enlace externo.
(énfasis-mío)
Eso explica el segundo ejemplo (tendré enlace interno). En cuanto al primero, estoy bastante seguro de que es un comportamiento indefinido:
7) Si, dentro de una unidad de traducción, aparece el mismo identificador con enlaces internos y externos, el comportamiento es indefinido.
... porque extern
aparece antes de que se declare el identificador con enlace interno, 6.2.2 / 4 no se aplica. Como tal, i
enlaces internos y externos, por lo que es UB.
Si el compilador emite un diagnóstico, bueno, afortunadamente, supongo. Se podría compilar sin errores y seguir cumpliendo con el estándar.