c++ - valores - Comportamiento extraño de variable global estática
variables globales y locales en visual basic (8)
Como complemento a todas las respuestas. POR QUÉ sucede, ya fue explicado. Sin embargo, CÓMO solucionarlo, se sugirió hasta ahora solo mediante el uso de un enfoque estático / externo. Esto es un poco como C Si no tiene que usar el encabezado en la parte C del proyecto con enlace C, podría usar C ++.
Entonces si realmente tienes que usar algo estático en tu código.
O bien declare la variable como miembro de una clase:
header.h
MyGlobalVariableHoler
{
public: static int i;
};
main.cpp
// class'' statics have has to be initialized, otherwise linker error.
int MyGlobalVariableHoler::i=0;
any_code.cpp
#include <header.h>
MyGlobalVariableHolder::i=4711;
O usa un singleton para evitar la inicialización explícita
header.h
MyGlobalVariableHolder
{
MyGlobalVariableHolder(){i=0;}
public:
static MyGlobalVariableHolder & instance()
{
static MyGlobalVariableHolder inst;
return inst;
}
int i;
};
any_code.cpp
#include <header.h>
MyGlobalVariableHolder::instance().i=4711;
Sé que este programa no está utilizando la variable estática de una manera adecuada, pero muestra cómo reproducir un comportamiento que he visto:
Main.cpp:
int main(){
MyObject* p = new MyObject();
Header::i = 5;
printf("i %i/n", Header::i);
p->update();
return 0;
}
MyObject.cpp:
MyObject::MyObject(){
}
void MyObject::update(){
printf("i %i/n", Header::i);
}
Extern.h:
namespace Header {
static int i;
};
La salida que obtengo es:
i : 5
i : 0
¿Por qué no obtengo 5
para ambas salidas? ¿De dónde viene este 0
? ¿Podrías explicar cómo funcionan las variables estáticas?
Es mejor declarar su variable con extern
en su archivo de encabezado para especificar que tiene un enlace externo. De lo contrario, se producirá el comportamiento anterior o pueden surgir problemas potenciales de compilación o enlace.
static int i ; // i has internal linkage
extern int i ; // i has external linkage
La variable que se declara estática solo tiene alcance en el archivo en el que se declara donde se puede acceder a la variable declarada sin estática desde otros archivos mediante una declaración externa.
Las variables estáticas tienen un enlace interno que efectivamente significa que son locales a la unidad de compilación. Ya que tiene la variable estática declarada en un encabezado incluido en 2 archivos de origen, básicamente tiene 2 variables distintas: una i
local a MyObject.cpp
y otra, diferente i
, local a main.cpp
No debes poner valiables estáticos en los archivos de cabecera. Eso lleva a cada archivo cpp que incluye ese encabezado para tener una copia de ese local estático en su unidad de compilación.
Lo que podrías hacer es un especificador de almacenamiento externo:
Encabezamiento:
namespace Header {
extern int i;
}
Cpp:
namespace Header {
int i = 0;
}
Se está confundiendo con la variable estática de nivel de clase con la variable estática de nivel de espacio de nombres. A ambos se accede mediante la calificación X::y
, lo que aumenta la confusión. Otros han explicado la razón real (a nivel de compilación / vinculación).
Tiene una variable estática por unidad de traducción en la que incluye el encabezado, porque las variables estáticas tienen vínculos internos.
¿De dónde viene este 0?
No ha inicializado la variable en la segunda unidad de traducción, y las variables estáticas están inicializadas en cero, de ahí proviene el 0.
En la norma (§3.6.2 / 2):
Las variables con duración de almacenamiento estático (3.7.1) se [...] inicializarán con cero (8.5) antes de que tenga lugar cualquier otra inicialización. [...]
Tienes dos variables i
static int i;
Porque tiene enlace interno. Eso significa que cada unidad de compilación donde se incluyó el encabezado correspondiente tiene su propio objeto i y otras unidades de compilación no saben nada sobre la presencia de ese objeto en esta unidad de compilación.
Si va a eliminar el especificador static
entonces el vinculador debe emitir un mensaje que indica que la variable está definida dos veces.
Se puede lograr el mismo efecto si se coloca una variable en un espacio de nombres sin nombre en C ++ 2011. Por ejemplo, en lugar de
namespace Header {
static int i;
};
usted podría escribir
namespace {
int i;
};
En este caso varaible i también tiene enlace interno. Esto es válido para C ++ 2011.