Объявления переменной в заголовочных файлах - статичный или нет?

86
задан sth 17 June 2014 в 15:12
поделиться

10 ответов

static средства, что будет одна копия VAL создана для каждого исходного файла, в который это включено. Но это также означает, что несколько включений не приведут к повторным определениям VAL, который столкнется во время ссылки. В C без static необходимо было бы удостовериться, что только один исходный файл определил VAL, в то время как другие исходные файлы объявили его extern. Обычно можно было бы сделать это путем определения его (возможно с инициализатором) в исходном файле и поместил бы extern объявление в заголовочном файле.

static переменные на глобальном уровне только видимы в их собственном исходном файле, добрались ли они там через то, чтобы включать или были в основном файле.

<час>

Примечание редактора: В C++, const объекты ни с static, ни с extern ключевые слова в их объявлении неявно static.

105
ответ дан M.M 24 November 2019 в 07:56
поделиться

static и extern наклеивает ограниченные по объему файлом переменные, определяют, доступны ли они в других единицах перевода (т.е. другой .c или .cpp файлы).

  • static дает переменную внутреннюю связь, скрывая его от других единиц перевода. Однако переменные с внутренней связью могут быть определены в нескольких единицах перевода.

  • extern дает переменную внешнюю связь, делая его видимым к другим единицам перевода. Обычно это означает, что переменная должна только быть определена в одной единице перевода.

значение по умолчанию (когда Вы не определяете static или extern) является одной из тех областей, по которым отличаются C и C++.

  • В C, ограниченные по объему файлом переменные extern (внешняя связь) по умолчанию. Если Вы используете C, VAL static, и ANOTHER_VAL extern.

  • В C++, ограниченные по объему файлом переменные static (внутренняя связь) по умолчанию, если они const, и extern по умолчанию, если они не. Если Вы используете C++, и VAL и ANOTHER_VAL static.

Из проекта спецификация C:

6.2.2 Связи идентификаторов...-5-, Если объявление идентификатора для функции не имеет никакого спецификатора класса памяти, его связь определяется точно, как будто оно было объявлено с экстерном спецификатора класса памяти. Если объявление идентификатора для объекта имеет объем файла и никакой спецификатор класса памяти, его связь является внешней.

Из проекта спецификация C++:

7.1.1 - Спецификаторы класса памяти [dcl.stc]...-6-имя, объявленное в объеме пространства имен без спецификатора класса памяти, имеет внешнюю связь, если это не имеет внутреннюю связь из-за предыдущего объявления и если это не объявляется константой. Objects объявил, что константа и не явно объявленный экстерн имеет внутреннюю связь.

109
ответ дан bk1e 24 November 2019 в 07:56
поделиться

Помехи будут означать, что Вы получаете одну копию на файл, но в отличие от других сказали, что совершенно законно сделать так. Можно легко протестировать это с небольшим примером кода:

test.h:

static int TEST = 0;
void test();

test1.cpp:

#include <iostream>
#include "test.h"

int main(void) {
    std::cout << &TEST << std::endl;
    test();
}

test2.cpp:

#include <iostream>
#include "test.h"

void test() {
    std::cout << &TEST << std::endl;
}

Выполнение этого дает Вам этот вывод:

0x446020
0x446040

46
ответ дан slicedlime 24 November 2019 в 07:56
поделиться

Статическое объявление на этом уровне кода означает, что переменная только видима в текущей единице компиляции. Это означает, что только кодируют в том модуле, будет видеть ту переменную.

, если у Вас есть заголовочный файл, который объявляет, переменные помехи и тот заголовок включены в несколько файлов C/CPP, тогда та переменная будет "локальна" для тех модулей. Будут копии N той переменной для мест N, что заголовок включен. Они не связаны друг с другом вообще. Любой код в любом из тех исходных файлов только сошлется на переменную, которая объявляется в том модуле.

В данном случае, 'статическое' ключевое слово, кажется, не предоставляет преимущества. Я мог бы пропускать что-то, но это, кажется, не имеет значение - я никогда не видел ничего сделанного как это прежде.

Что касается встраивания, в этом случае переменная, вероятно, встраивается, но это - то, только потому, что это объявило константу. Компилятор мог бы для, более вероятно, встраивания статических переменных модуля, но это зависит от ситуации и скомпилированного кода. Нет никакой гарантии, что компилятор встроит 'помехи'.

5
ответ дан Mark 24 November 2019 в 07:56
поделиться

Книга C (бесплатно онлайн) имеет главу о связи, которая объясняет значение 'статических' более подробно (хотя корректный ответ уже дан в других комментариях): http://publications.gbdirect.co.uk/c_book/chapter4/linkage.html

2
ответ дан Jan de Vos 24 November 2019 в 07:56
поделиться

Для ответа на вопрос "помехи означают, что только одна копия VAL создается, в случае, если заголовок включен больше чем одним исходным файлом?"...

НИКАКОЙ . VAL будет всегда определяться отдельно в каждом файле, который включает заголовок.

стандарты для C и C++ действительно вызывают различие в этом случае.

В C, ограниченные по объему файлом переменные являются экстерном по умолчанию. При использовании C VAL статичен, и ANOTHER_VAL является экстерном.

Примечание, что современные компоновщики могут жаловаться на ANOTHER_VAL, если бы заголовок включен в различные файлы (то же глобальное имя, определенное дважды), и определенно жаловался бы, был ли ANOTHER_VAL инициализирован к различному значению в другом файле

В C++, ограниченные по объему файлом переменные статичны по умолчанию, если они - константа и экстерн по умолчанию, если они не. При использовании C++ и VAL и ANOTHER_VAL статичны.

также необходимо принять во внимание то, что обе переменные определяются константа Идеально, компилятор всегда принимал бы решение встроить эти переменные и не включать любое устройство хранения данных для них. Существует большое количество причин, почему устройство хранения данных может быть выделено. Я могу думать...

  • параметры отладки
  • адрес, взятый в компиляторе файла
  • всегда, выделяет устройство хранения данных (сложные типы константы не могут легко быть встроены, поэтому становится особым случаем для основных типов)
2
ответ дан itj 24 November 2019 в 07:56
поделиться

Предположение, что эти объявления в глобальной области видимости (т.е. не членские переменные), тогда:

статичный означает 'внутреннюю связь'. В этом случае, так как это объявляется константа , это может быть оптимизировано/встроено компилятором. Если Вы опускаете константа тогда, компилятор должен выделить устройство хранения данных в каждой единице компиляции.

Путем исключения статичный связь экстерн по умолчанию. Снова, Вы были сохранены константа мыс - компилятор может оптимизировать/встроить использование. Если Вы отбросите константа тогда, то Вы доберетесь , умножают определенные символы ошибка во время ссылки.

1
ответ дан Seb Rose 24 November 2019 в 07:56
поделиться

Статичный предотвращает другую единицу компиляции от externing, что переменная так, чтобы компилятор мог просто "встроить" значение переменной, где это используется и не создает устройство хранения данных памяти для него.

В Вашем втором примере, компилятор не может предположить, что некоторый другой исходный файл не будет экстерн это, таким образом, это должно будет на самом деле сохранить то значение в памяти где-нибудь.

0
ответ дан Jim Buck 24 November 2019 в 07:56
поделиться

Статичный препятствует тому, чтобы компилятор добавил несколько экземпляров. Это становится менее важным с #ifndef защитой, но принятие заголовка включено в две отдельных библиотеки, и приложение связано, два экземпляра были бы включены.

-2
ответ дан Superpolock 24 November 2019 в 07:56
поделиться

const переменные в C ++ имеют внутреннюю связь. Таким образом, использование static не имеет никакого эффекта.

a.h

const int i = 10;

one.cpp

#include "a.h"

func()
{
   cout << i;
}

two.cpp

#include "a.h"

func1()
{
   cout << i;
}

Если бы это была программа на C, вы бы получили ошибку «множественное определение» для i (из-за внешней связи).

6
ответ дан 24 November 2019 в 07:56
поделиться