Статические переменные в C и C ++ - PullRequest
16 голосов
/ 27 марта 2010

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

Ответы [ 5 ]

16 голосов
/ 27 марта 2010

Нет, в этом отношении нет разницы между C и C ++.

Прочитайте этот SO-ответ о том, что static означает в программе на Си. В C ++ есть несколько других значений, связанных с использованием static для переменных класса (вместо переменных экземпляра).

Относительно глобальных переменных, являющихся static - только с точки зрения распределения памяти (они расположены в сегменте данных, как и все глобальные переменные) С точки зрения видимости:

static int var;    // can't be seen from outside files
int var;           // can be seen from outside files (no 'static')
7 голосов
/ 27 марта 2010

Здесь есть два понятия: "статическое связь (или область действия)" и статическое распределение".

За пределами функции ключевое слово относится к связыванию, внутри оно относится к распределению. Все переменные вне функции имеют статическое распределение неявно. Возможно, неудачный дизайн, но он есть.

5 голосов
/ 27 марта 2010

C и C ++ одинаковы.

static делает две разные вещи.

Для переменных, объявленных вне области действия функции, она изменяет видимость (связь) переменной. Переменная будет глобальной переменной, поскольку она находится за пределами области действия функции. Если оно не статично, оно будет иметь универсальную связь (видимость), поэтому любой код, связанный с этим, может получить к нему доступ (возможно, им придется объявить его extern). Если переменная находится вне области действия функции и является статической, она по-прежнему является глобальной переменной в том смысле, что она всегда существует и сохраняет свое значение, но никакой код вне одной и той же единицы компиляции (этот файл .c и любые включенные .h) не может получить к нему доступ.

Для переменных, объявленных внутри области действия функции, static изменяет местоположение, где хранится переменная. Если оно не является статическим, это будет автоматическая переменная, это означает, что она исчезает при выходе из функции и возвращается к существованию (в стеке) при повторном вводе функции. Это теряет значение при выходе из функции. А также любые ссылки на него (указатели на него) недействительны после выхода из функции. Если переменная, объявленная внутри области действия функции, является статической, то это делает ее не автоматической, а глобальной переменной. Таким образом, переменная будет существовать после выхода из функции и, таким образом, будет сохранять свое значение при вызовах функции, а также любые ссылки (указатели) на нее действительны даже после выхода из функции. Обратите внимание, что в обоих случаях область видимости переменной находится только внутри этой функции, поэтому получить к ней доступ напрямую (но только через сохраненную ссылку) невозможно из-за пределов области действия функции.

Последнее, что делает static, - это когда запускается инициализатор (т.е. int foo = 5) для переменной. Для всех случаев, когда распределение является глобальным (каждый случай, кроме автоматического), инициализатор запускается только один раз, в начале выполнения вашей программы. Он запускается до запуска main (), поэтому вы можете получить не совсем ожидаемый результат, если ваш инициализатор не просто постоянное число, а выполняет некоторый код. Для автоматического случая инициализатор запускается каждый раз, когда вводится функция, и в этом случае он всегда выполняется после ввода main ().

1 голос
/ 27 марта 2010

Я хочу добавить к ответу Южного гостеприимства Статические переменные в C и C ++

следующие замечания:

Использование static для обозначения "local to translation unit" не рекомендуется в C ++ (href = "https://rads.stackoverflow.com/amzn/click/com/0201700735" rel =" nofollow noreferrer "Язык программирования C ++: специальное издание, приложение B.2.3, устаревшие функции) .

Вместо этого следует использовать безымянные пространства имен:

static int reply = 42; // deprecated

namespace {
    int reply1 = 42;  // The C++ way
}

Как уже сказал Southern Hospitality, порядок инициализации глобальных объектов не определен. В этой ситуации вам следует рассмотреть возможность использования шаблона href = "http://en.wikipedia.org/wiki/Singleton_pattern#C.2B.2B", Singleton.

UPDATE: GMan прокомментировал мой ответ:

«Порядок определяется для каждой единицы перевода ...»: это действительно забило мне голову, поэтому я посмотрел его на языке программирования C ++.

В Разделе 9.4.1, Инициализация нелокальных переменных, профессор Страуструп предлагает, что «функция, возвращающая ссылку, является хорошей альтернативой глобальной переменной»:

int& use_count()
{
        static int uc = 0;
        return uc;
}

"Вызов use_count() теперь действует как глобальная переменная, которая инициализируется при первом ее использовании. Например:"

void f()
{
        std::cout << ++use_count() << '\n';
}

В моем понимании это очень похоже на паттерн Синглтона.

GMan прокомментировал далее: «Мы должны ограничить нашу способность создавать эти объекты одним и предоставлять глобальный доступ к ним». Действительно ли ограничение одного связано с чем-то в этой проблеме? Нам может понадобиться глобально, но кто скажет, что мы не хотим его в других местах? "

Некоторые цитаты из синглтона (127) (Gamma et al, Design Patterns):

«Шаблон Singleton является улучшением по сравнению с глобальными переменными. Он не допускает загрязнения пространства имен глобальными переменными, в которых хранятся отдельные экземпляры.»

«Шаблон позволяет легко передумать и разрешить более одного экземпляра класса Singleton».

Синглтоны инициализируются в порядке их первого использования.

В Herb Sutter, Андрей Александреску, Стандарты кодирования C ++, пункт 10 гласит:

"Избегайте общих данных, особенно глобальных данных."

Поэтому я часто использую Singletons, чтобы избежать глобальных данных. Но, конечно, поскольку все слишком много, это может быть чрезмерное использование шаблона Singleton. (Джошуа Кериевский называет это «синглтонитом» в своей книге «Рефакторинг на паттерны».)

ОБНОВЛЕНИЕ 2:

(Извините, но я не могу писать комментарии, поэтому это обновление.)

Джальф написал в своем комментарии: «Бригада из четырех человек курила что-то нелегальное, когда писала о схеме синглтона».

Очевидно, что другие разработчики C ++ тоже курили интересные вещества. Например, Херб Саттер (он более десяти лет работал секретарем и председателем комитета по стандартам ISO C ++ во время разработки второго стандарта C ++, C ++ 0x, и в качестве ведущего архитектора C ++ / CLI в Microsoft. В настоящее время Херб разработчик модели памяти Prism для платформ Microsoft и расширений Concur для Visual C ++ для параллельного программирования), написанный в C ++ Стандарты кодирования, пункт 21:

"Когда вам нужна такая (на уровне пространства имен) переменная, которая может зависеть от другой, рассмотрите шаблон проектирования Singleton; при осторожном использовании он может избежать неявных зависимостей, гарантируя, что объект инициализируется при первом доступе. Тем не менее, Singleton является глобальная переменная в овечьей шкуре и нарушается взаимными или циклическими зависимостями. "

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

Обратите внимание, что в языке Java глобальные данные даже не существуют. Очевидно, что глобальные данные заменяются / эмулируются с помощью шаблона проектирования Singleton.

(Поскольку я работаю в своей дневной работе с командой Java, я стремлюсь к максимальному сходству моих программ на C ++ с программами Java. Например, каждый класс находится в своем собственном исходном файле / модуле перевода.)

0 голосов
/ 27 марта 2010

Не совсем прямой ответ на ваш вопрос, но что-то тесно связанное, на что следует обратить внимание, если вы используете и C, и C ++.

В C ++, в отличие от C, глобальные переменные, которые объявлены как «const», неявно локальны для единицы перевода, AS IF использовало «static».

Пример:

// file A
extern const int glob;

// file B
const int glob = 42;

Это будет работать, если вы используете компилятор C, но не используете компилятор C ++. В C ++ переменная glob в файле B не может использоваться из файла A, и компоновщик выдаст ошибку «неразрешенная ссылка».

...