Он используется как в C, так и в C ++.
Как вы уже догадались, static
часть ограничивает свою область действия этой единицей компиляции . Также предусмотрена статическая инициализация. const
просто говорит компилятору не позволять никому его изменять. Эта переменная помещается либо в сегмент данных, либо в сегмент bss, в зависимости от архитектуры, и может находиться в памяти, помеченной только для чтения.
Все это то, как C обрабатывает эти переменные (или как C ++ обрабатывает переменные пространства имен). В C ++ отмеченный член static
используется всеми экземплярами данного класса. Независимо от того, является ли она частной или нет, это не влияет на то, что одна переменная используется несколькими экземплярами. Наличие const
там предупредит вас, если какой-либо код попытается это изменить.
Если бы он был строго закрытым, то каждый экземпляр класса получал бы свою собственную версию (несмотря на оптимизатор).
Многие люди дали основной ответ , но никто не указал, что в C ++ по
const
умолчанию , чтобыstatic
наnamespace
уровне (а некоторые дали неверную информацию). См. Стандартный раздел 3.5.3 C ++ 98.Сначала немного предыстории:
Единица перевода: исходный файл после препроцессора (рекурсивно) включал все его включаемые файлы.
Статическая связь: символ доступен только в пределах своей единицы перевода.
Внешняя ссылка: символ доступен из других единиц перевода.
На
namespace
уровнеЭто включает в себя глобальное пространство имен, также известное как глобальные переменные .
На функциональном уровне
static
означает, что значение сохраняется между вызовами функций.Семантика функциональных
static
переменных аналогична глобальным переменным в том смысле, что они находятся в сегменте данных программы (а не в стеке или куче); см. Этот вопрос для получения дополнительных сведений о времениstatic
жизни переменных.На
class
уровнеstatic
означает, что значение распределяется между всеми экземплярами класса иconst
не изменяется.источник
const int *foo(int x) {const int b=x;return &b};
зависимостиconst int *foo(int x) {static const int b=x;return &b};
const
только о подразумеваемыхstatic
в последнем случае.const
декларация также подразумеваетstatic
? Например, если вы отброситеconst
и измените значение, все значения будут изменены?const
не подразумевает статичность на уровне функций, это было бы кошмаром параллелизма (const! = Постоянное выражение), все на уровне функции неявноauto
. Поскольку этот вопрос также помечен тегом [c], я должен упомянуть, что глобальный уровеньconst int
неявно находитсяextern
в C. Однако правила, которые у вас здесь, прекрасно описывают C ++.static
указывает, что переменная имеет статическую продолжительность (существует только одна копия, которая длится от начала до конца программы) и имеет внутреннюю / статическую связь, если не указано иное (это отменяется функцией связывание для локальных статических переменных или связывание класса для статических членов). Основные различия заключаются в том, что это означает в каждой ситуации, когдаstatic
это действительно так.Эта строка кода может фактически появляться в нескольких разных контекстах, и хотя она ведет себя примерно одинаково, есть небольшие различия.
Область действия пространства имен
'
i
' будет отображаться во всех единицах перевода, которые включают заголовок. Однако, если вы на самом деле не используете адрес объекта (например. '&i
'), Я почти уверен, что компилятор будет рассматривать 'i
' просто как типобезопасный0
. Если еще две единицы трансляции принимают '&i
', то адрес для каждой единицы трансляции будет другим.'
i
' имеет внутреннюю связь, поэтому на него нельзя ссылаться извне этой единицы перевода. Однако, опять же, если вы не используете его адрес, он, скорее всего, будет рассматриваться как типобезопасный0
.Стоит отметить, что следующее объявление:
является точно так же , как
static const int i = 0
. Переменная в пространстве имен, объявленная с помощьюconst
и не объявленная явно с помощьюextern
, неявно статична. Если вы думаете об этом, то намерением комитета C ++ было разрешитьconst
объявлять переменные в файлах заголовков без необходимости всегда использоватьstatic
ключевое слово, чтобы избежать нарушения ODR.Область действия класса
В приведенном выше примере стандарт явно указывает, что "
i
" не нужно определять, если его адрес не требуется. Другими словами, если вы используете только "i
" как типобезопасный 0, компилятор не будет определять его. Одно различие между версиями класса и пространства имен заключается в том, что адрес 'i
' (если используется в двух или более единицах перевода) будет одинаковым для члена класса. Если используется адрес, вы должны иметь для него определение:источник
Это небольшая оптимизация пространства.
Когда ты говоришь
Вы не определяете константу, а создаете переменную только для чтения. Компилятор достаточно умен, чтобы использовать 42 всякий раз, когда видит foo, но он также выделяет для него место в области инициализированных данных. Это сделано потому, что, как определено, foo имеет внешнюю связь. Другой модуль компиляции может сказать:
extern const int foo;
Чтобы получить доступ к его стоимости. Это не очень хорошая практика, поскольку этот модуль компиляции не знает, каково значение foo. Он просто знает, что это const int, и должен перезагружать значение из памяти всякий раз, когда оно используется.
Теперь, объявив, что он статический:
Компилятор может выполнять свою обычную оптимизацию, но он также может сказать: «Эй, никто за пределами этого модуля компиляции не может видеть foo, и я знаю, что это всегда 42, поэтому нет необходимости выделять для него какое-либо пространство».
Я также должен отметить, что в C ++ предпочтительный способ предотвратить экранирование имен из текущей единицы компиляции - использовать анонимное пространство имен:
источник
Отсутствует int. Так должно быть:
В C и C ++ он объявляет целочисленную константу со значением 42 в области локального файла.
Почему 42? Если вы еще не знаете (и трудно поверить, что вы не знаете), это отсылка к Ответу на жизнь, Вселенную и все остальное .
источник
В C ++
- это предпочтительный способ определения и использования констант. Т.е. используйте это, а не
потому что это не подрывает систему безопасности типов.
источник
Ко всем отличным ответам я хочу добавить небольшую деталь:
Если Вы пишете плагины (например, библиотеки DLL или .so для загрузки в систему САПР), то static - это спасатель, который позволяет избежать конфликтов имен, подобных этому:
Еще хуже: шаг 3 может вести себя по-разному в зависимости от оптимизации компилятора, механизма загрузки плагина и т. Д.
Однажды у меня была эта проблема с двумя вспомогательными функциями (одно и то же имя, разное поведение) в двух плагинах. Объявление их статическими решило проблему.
источник
Согласно спецификации C99 / GNU99:
static
спецификатор класса хранения
объекты области файлового уровня по умолчанию имеют внешнюю связь
const
является квалификатором типа (является частью типа)
ключевое слово применяется к непосредственному левому экземпляру - т.е.
MyObj const * myVar;
- неквалифицированный указатель на квалифицированный тип объекта constMyObj * const myVar;
- квалифицированный указатель const на неквалифицированный тип объектаКрайнее левое использование - применяется к типу объекта, а не к переменной
const MyObj * myVar;
- неквалифицированный указатель на квалифицированный тип объекта constТАКОЙ:
static NSString * const myVar;
- постоянный указатель на неизменяемую строку с внутренней связью.Отсутствие
static
ключевого слова сделает имя переменной глобальным и может привести к конфликту имен в приложении.источник
inline
Переменные C ++ 17Если вы погуглили "C ++ const static", то, скорее всего, вы действительно хотите использовать встроенные переменные C ++ 17 .
Эта замечательная функция C ++ 17 позволяет нам:
constexpr
: Как объявить constexpr extern?main.cpp
notmain.hpp
notmain.cpp
Скомпилируйте и запустите:
GitHub вверх по течению .
См. Также: Как работают встроенные переменные?
Стандарт C ++ для встроенных переменных
Стандарт C ++ гарантирует, что адреса будут такими же. Стандартный черновик 10.1.6 C ++ 17 N4659 «Встроенный спецификатор»:
cppreference https://en.cppreference.com/w/cpp/language/inline объясняет, что если
static
не указан, то он имеет внешнюю связь.Реализация встроенной переменной GCC
Мы можем наблюдать, как это реализовано с помощью:
который содержит:
и
man nm
говорит оu
:Итак, мы видим, что для этого есть специальное расширение ELF.
До C ++ 17:
extern const
До C ++ 17 и в C мы могли добиться очень похожего эффекта с помощью
extern const
, что привело бы к использованию одной области памяти.Минусы
inline
:constexpr
с помощью этого метода, толькоinline
позволяет следующее: Как объявить constexpr extern?main.cpp
notmain.cpp
notmain.hpp
GitHub вверх по течению .
Альтернативы только для заголовков до C ++ 17
Это не так хорошо, как
extern
решение, но они работают и занимают только одну ячейку памяти:constexpr
Функция, потому чтоconstexpr
подразумеваетinline
иinline
позволяет (сил) определение появляться на каждом ЕП :и я уверен, что любой достойный компилятор встроит вызов.
Вы также можете использовать переменную
const
илиconstexpr
static, как в:но вы не можете делать такие вещи, как получение его адреса, иначе он станет использоваться odr, см. также: Определение статических членов данных constexpr
С
В C ситуация такая же, как и в C ++ до C ++ 17, я загрузил пример по адресу: Что означает «статический» в C?
Единственное отличие состоит в том, что в C ++
const
подразумеваетсяstatic
для глобальных объектов, но не в C: семантика C ++ static const и const.Есть ли способ полностью встроить его?
TODO: есть ли способ полностью встроить переменную без использования памяти?
Очень похоже на то, что делает препроцессор.
Это потребует как-то:
Связанный:
Протестировано в Ubuntu 18.10, GCC 8.2.0.
источник
Да, он скрывает переменную в модуле от других модулей. В C ++ я использую его, когда мне не нужно / не нужно изменять файл .h, который вызовет ненужную перестройку других файлов. Кроме того, я сначала поставил статику:
Кроме того, в зависимости от его использования, компилятор даже не будет выделять для него хранилище, а просто «встроит» значение, в котором оно используется. Без статики компилятор не может предположить, что он не используется где-либо еще и не может быть встроен.
источник
Это глобальная константа, видимая / доступная только в модуле компиляции (файл .cpp). Кстати, использование static для этой цели устарело. Лучше использовать анонимное пространство имен и перечисление:
источник
enum
этого в данном контексте. Хотите уточнить? Такиеenums
, как правило , используется только для предотвращения компилятору выделения любого пространства для значения (хотя современные компиляторы не нужен этотenum
хак для него) и предотвратить создание указателей на значения.Если сделать его закрытым, он все равно появится в заголовке. Я предпочитаю использовать «самый слабый» способ. См. Эту классическую статью Скотта Мейерса: http://www.ddj.com/cpp/184401197 (речь идет о функциях, но здесь также можно применить).
источник