2010-10-03 20 views
8

Hola Estoy estudiando para mi prueba en C y me he encontrado con una pregunta que no puedo entender su respuesta.una variable estática en c

Un programador escribió un programa para contar el número de usuarios (Count.h, Count.c):

/******** FILE: Counter.h ***********/ 
static int counter = 0; 
int getUsersNum(); 
/******** END OF FILE: Counter.h ****/ 

/******** FILE: Counter.c ***********/ 
#include "Counter.h" 
int getUsersNum() 
{ 
    return counter; 
} 
/******** END OF FILE: Counter.c ****/ 

Y un probador para probarlo:

/******** FILE: CounterMain.c ***********/ 
#include "Counter.h" 
#include <stdio.h> 
int main() 
{ 
    int i; 
    for (i=0;i<5;++i) 
    { 
     ++counter; 
     printf ("Users num: %d\n", getUsersNum()); 
    } 
    return 0; 
} 
/******** END OF FILE: CounterMain.c ****/ 

Sorprendentemente la salida fue:

Users num: 0 
Users num: 0 
Users num: 0 
Users num: 0 
Users num: 0 

No puedo ver por qué con este uso de la variable estática el contador no avanza ... ¿por qué obtuvieron tales ¿entrada?

gracias a todos!

Respuesta

12

Solo piénselo como ".h archivos no existen". Lo que ocurre es que los archivos .h se incluyen dentro de los archivos .c y solo los archivos .c se compilan (y se vinculan (mezclan)).

En el caso de tener 2 archivos .c con

static int counter = 0; 

Cada counter es específico para el archivo .c que se encuentra. El counter en CounterMain.c es una variable diferente que el counter facturación. do.

Necesita tener uno solo definición de contador. Puede tener varias declaraciones (típicamente en .h)

/* .h file */ 
extern int counter; 

/* .c file(s) that use the counter but don't define it */ 
#include "file.h" 

/* .c file that **defines** counter */ 
#include "file.h" 
int counter = 0; 

Ohhhhhhhhhhhhhhhhhh y no es lo static. No lo use en el alcance global!

+2

+1 por publicar una explicación simple y solución en lugar de pasar por muchos detalles precisos pero sangrientos. –

14

En C, el alcance de una variable estática es el archivo fuente en el que está definido.

Dado que está cargando este encabezado en 2 archivos .c separados, cada archivo obtiene una variable única. Incrementar el "contador" en un archivo no afecta la variable "estática" en el otro archivo.

Para obtener más información, consulte this description. Para que la variable sea visible y se comparta en varios archivos, debe declararse como extern. De lo contrario:

estáticas Las variables globales: las variables declaradas como estática en el nivel superior de un archivo de origen (fuera de cualquier definición de función) son visibles a lo largo de ese archivo ("File alcance").

Cual es el caso aquí.

+4

"Archivo de origen" es confuso porque un archivo de encabezado es un archivo de origen y la variable solo se declara en un archivo de origen. _La unidad de traducción_ sería más precisa. –

+2

'En C, el alcance de una variable estática es el archivo fuente en el que se define'. Es posible que desee reemplazar 'archivo de origen' con' unidad de traducción'. –

+0

@Charles: ¡Demasiado rápido! Estaba publicando exactamente lo mismo. : D –

1

Una variable static solo está disponible en el archivo en el que está definida. En este ejemplo, Counter.c y CounterMain.c tienen su propia variable counter.

Cuando se ejecuta ++counter, esto actualiza la variable declarada en CounterMain.c. Pero cuando se llama a getUsersNum(), esto devuelve el valor de la variable counter de Counter.c, que no se ha incrementado.

Si cambia getUsersNum() a counter, verá que la variable counter declarada en CounterMain.c se ha incrementado.

2

La palabra clave static significa, cuando se usa para calificar funciones o variables globales, que la función o variable debe tener internal linkage, lo que significa que no debe ser visible como un símbolo global. Por lo tanto, cada unidad de compilación que incluye Counter.h tendrá su propia copia local de counter que no chocará con otras.

En este caso, Counter.c y CounterMain.c tienen diferentes variables count, dando como resultado lo que usted ha descrito.

La solución es cambiar la definición de counter en Counter.h a una declaración:
extern int counter;
y poner la definición de Counter.c:
int counter = 0;

Después CounterMain y cualesquiera otras unidades de compilación que incluye Counter.h debe ser puede acceder a la única instancia counter, pero es posible que desee disfrutar de information hiding y solo acceder a ella a través de funciones en Counter, dando como resultado un limpiador interface.

+1

¿En qué se diferencia 'static' para funciones y variabls? –

+0

@Charles Bailey Es diferente una vez que profundizas en el código generado, pero si miras solo en el nivel C, es semánticamente más o menos lo mismo. – zneak

+0

No es para funciones y variables globales: Cambia el enlace como lo he explicado (he editado mi respuesta para que diga "variable o función"). Con variables locales simples, significa "almacenamiento estático y vida útil", es decir, una vieja variable estática simple. – aib

1

Se debe a que la variable estática se declara en el encabezado. En C, las variables estáticas solo existen en el archivo .c en el que están declaradas. Como su .h está incluido (las directivas #include pueden verse como nada más que una operación de copiar y pegar) en dos archivos .c distintos, se crean dos variables estáticas llamadas counter, una en cada archivo. Su archivo de prueba incrementa su variable local counter, pero la que devuelve getUsersNum es de otro archivo C y es completamente independiente.

Lo que intenta hacer la pregunta es acceder a una variable estática de un archivo distinto de aquel en el que se declaró. Debes saber que no es (directamente) posible. Para incrementar el contador correcto, necesitará una función que opere en la variable Contador.ccounter.

3

static int counter = 0;

Si una variable se ha definido utilizando el especificador de clase de almacenamiento estático la variable tiene un internal linkage. Eso significa que puede usar counter dentro del mismo translation unit en el que está definido.

3

Un programa en C se crea combinando una o más unidades de traducción para crear un programa.

A unidad de traducción es, en efecto, un archivo fuente preprocesado.Contiene cualquier encabezado incluido y archivos fuente especificados en las directivas #include, y excluye todo lo excluido por #if o directivas similares.

Cuando se declara una variable en el alcance del archivo static, da el nombre de la variable enlace interno. Esto significa que el nombre se refiere a un objeto local de la unidad de traducción en la que aparece. Si el nombre se usa en otra unidad de traducción y no puede referirse al objeto en esta unidad de traducción, debe referirse a un objeto diferente.

[Por el contrario, un nombre con enlace externo se refiere al mismo objeto que sea traducción unidad el nombre se utiliza en.]

static int counter = 0; 

Cuando se pone una declaración como esta en un archivo de cabecera, que significa que cada unidad de traducción que incluye el archivo de encabezado tiene su propio objeto único llamado counter que es distinto de cualquier objeto llamado counter en cualquier otra unidad de traducción.

En su caso, hay uno counter en la unidad de traducción generada a partir de CounterMain.c y otro en la unidad de traducción generar desde Count.c. El que está en Count.c nunca se incrementa, pero lo devuelve getUserNum(), el de CounterMain.c se incrementa en main pero nunca se lo utiliza en ningún otro lado.

Cuestiones relacionadas