2010-10-03 8 views
8

Привет Я изучаю для своего теста в C, и я столкнулся с вопросом, который я не могу понять.статическая переменная в c

Программист написал программу для подсчета количества пользователей (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 ****/ 

И тестера проверить:

/******** 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 ****/ 

Suprisingly выход был:

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

Не могу понять, почему при использовании статической переменной счетчик не продвигается .. почему они получили такие вход?

спасибо, что вы все!

ответ

12

Просто подумайте, что «файлы .h не существуют». Случается, что файлы .h включены в файлы .c, и только .c файлы компилируются (и связаны (смешанные) вместе).

В вашем случае у вас есть 2 .c файлы с

static int counter = 0; 

Каждый counter специфичен для файла .c он находится. counter в CounterMain.c это другая переменная, чем counter в счетчике. с.

Необходимо иметь определение счетчика. Вы можете иметь несколько объявлений (как правило, в заголовочных файлах)

/* .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 и есть еще static вещь. Не используйте его в глобальном масштабе!

+2

+1 для публикации простого объяснения и решения вместо того, чтобы проходить через множество точных, но подробных деталей. –

14

В C область действия статической переменной является исходным файлом, в котором она определена.

Поскольку вы загружаете этот заголовок в 2 отдельных файла .c, каждый файл получает уникальную переменную. Увеличение «счетчика» в одном файле не влияет на «статическую» переменную в другом файле.

Подробнее см. this description. Чтобы переменная отображалась и делилась в нескольких файлах, она должна быть объявлена ​​как extern. В противном случае:

Статические глобальные переменные: переменные, объявленные как статические на верхнем уровне исходного файла (вне любых определений функций), видимы в этом файле («область действия»).

Какой здесь случай.

+4

«Исходный файл» запутан, потому что заголовочный файл является исходным файлом, и переменная объявляется только в одном исходном файле. _Translation unit_ будет более точной. –

+2

'В C область статической переменной является исходным файлом, в котором она определена. Возможно, вы захотите заменить «исходный файл» на «единица перевода». –

+0

@Charles: Слишком быстро! Я отправлял то же самое. : D –

1

Переменная доступна только в том файле, в котором она определена. В этом примере Counter.c и CounterMain.c оба имеют свою собственную переменную counter.

Выполняется, когда ++counter обновляет переменную, указанную в CounterMain.c. Но когда вызывается getUsersNum(), это возвращает значение переменной counter от Counter.c, которое не было увеличено.

Если изменить getUsersNum() к counter, вы увидите counter переменную, объявленную в CounterMain.c было увеличивается.

2

Ключевое слово static означает, что при использовании для квалификации функций или глобальных переменных функция или переменная должна иметь internal linkage, что означает, что она не должна быть видимой в качестве глобального символа. Поэтому каждая единица компиляции, включая Counter.h, будет иметь свою локальную копию counter, которая не будет конфликтовать с другими.

В этом случае Counter.c и CounterMain.c имеют разные переменные count, в результате чего вы описали.

Решение изменить определение counter в Counter.h к объявлению:
extern int counter;
и поместить определение в Counter.c:
int counter = 0;

После CounterMain и любые другие единицы компиляции, включая Counter.h должны быть может получить доступ к одному экземпляру counter, но вы можете захотеть получить information hiding и получить доступ к нему только через функции в Counter, в результате чего очиститель interface.

+1

Как 'static' отличается для функций и variabls? –

+0

@Charles Bailey. Другое дело, когда вы вникаете в сгенерированный код, но если вы посмотрите только на уровень C, это семантически почти то же самое. – zneak

+0

Это не для функций и глобальных переменных: он меняет связь, как я объяснил (я отредактировал свой ответ, чтобы прочитать «переменная или функция»). С помощью простых локальных переменных это означает «статическое хранилище и время жизни», т. Е. Простая старая статическая переменная. – aib

1

Это потому, что статическая переменная объявлена ​​в заголовке. В C статические переменные существуют только в файле .c, в котором они объявлены. Поскольку ваш .h включен (#include директивы можно рассматривать как не более чем операцию копирования) в двух разных файлах .c, создаются две статические переменные с именем counter, по одному в каждом файле. Ваш тестовый файл увеличивает свою локальную переменную counter, но возвращаемый getUsersNum из другого файла C и полностью независим.

Вопрос, который пытается решить, - это получить доступ к статической переменной из файла, отличного от того, в котором он был объявлен. Вы должны знать, что это невозможно (прямо). Чтобы увеличить правый счетчик, вам понадобится функция, которая работает с переменной Counter.ccounter.

3

static int counter = 0;

Если переменная была определена с помощью статического класса для хранения Спецификатор переменная имеет internal linkage. Это означает, что вы можете использовать counter внутри того же translation unit, в котором он определен.

3

Программа A C производится путем объединения одного или нескольких единиц перевода вместе для составления программы.

A единица перевода является, по сути, предварительно обработанным исходным файлом.Он содержит любые включенные заголовки и исходные файлы, указанные в директивах #include, и исключает все, что исключено #if или аналогичные директивы.

Когда переменная в области файла объявлена ​​static, она дает имя переменной внутренняя связь. Это означает, что имя относится к локальному объекту для единицы перевода, в которой он отображается. Если имя используется в другой единицы перевода, то оно не может ссылаться на объект в этом модуле перевода, оно должно ссылаться на другой объект.

[В отличие от этого, имя с внешним связыванием относится к тому же объекту любой ЕП имя используется в.]

static int counter = 0; 

Когда вы кладете заявление, например, как это в файле заголовка, это означает, что каждая единица перевода, которая включает файл заголовка, имеет свой собственный уникальный объект с именем counter, который отличается от любого объекта с именем counter в любой другой единицы перевода.

В вашем случае есть counter в единицах перевода, созданных с CounterMain.c, а отдельный в единицах перевода - от Count.c. Значение в Count.c никогда не увеличивается, но возвращается getUserNum(), тот, что находится в CounterMain.c, увеличивается в main, но никогда не используется нигде.

Смежные вопросы