статическая переменная в с - PullRequest
8 голосов
/ 03 октября 2010

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

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

Удивительно, но результат был:

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

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

спасибо всем!

Ответы [ 7 ]

14 голосов
/ 03 октября 2010

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

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

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

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

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

12 голосов
/ 03 октября 2010

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

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

static int counter = 0;

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

Вам необходимо иметь один один определение счетчика. Вы можете иметь несколько объявлений (обычно в .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;

Оххххххххххххххххх и есть вещь static. Не используйте его в глобальном масштабе!

3 голосов
/ 03 октября 2010

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

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

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

[Напротив, имя с внешней связью относится к одному и тому же объекту независимо от того, в какой единице перевода используется имя.]

static int counter = 0;

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

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

3 голосов
/ 03 октября 2010

static int counter = 0;

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

2 голосов
/ 03 октября 2010

Ключевое слово 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 голос
/ 03 октября 2010

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

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

1 голос
/ 03 октября 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...