Что означает "const static" в C и c++?
const static int foo = 42;
Я видел это в каком-то коде здесь, на StackOverflow, и я не мог понять, что он делает. Затем я увидел некоторые путаные ответы на других форумах. Мое лучшее предположение, что он используется в C, чтобы скрыть константу foo из других модулей. Это правильно? Если да, то зачем кому-то использовать его в контексте C++, где вы можете просто сделать это private?
11 ответов:
Он имеет использование как в C, так и в C++.
как вы догадались,
staticчасть ограничивает свою область действия этим единица компиляции. Он также обеспечивает статическую инициализацию.constпросто говорит компилятору не позволять никому изменять его. Эта переменная либо помещается в сегмент data, либо BSS в зависимости от архитектуры, и может быть помечена в памяти только для чтения.все это то, как C обрабатывает эти переменные (или как C++ обрабатывает переменные пространства имен). В C++ член с пометкой
staticявляется общим для всех экземпляров данного класса. Является ли она частной или нет, не влияет на то, что одна переменная совместно используется несколькими экземплярами. Имеяconston там предупредит вас, если какой-либо код попытается изменить это.если бы он был строго частным, то каждый экземпляр класса получил бы свою собственную версию (несмотря на оптимизатор).
много людей дали ответ, но никто не указал, что в C++
constпо умолчаниюstaticatnamespaceуровень (и некоторые дали неверную информацию). Увидеть стандарта C++98 раздел 3.5.3.во-первых, некоторые фона:
перевод блок: исходный файл после препроцессора (рекурсивно) включал все его включенные файлы.
статическая линковка: символ доступен только в его переводе блок.
внешняя связь: символ из других единиц трансляции.
At
namespaceуровеньэто включает в себя глобальное пространство имен aka глобальные переменные.
static const int sci = 0; // sci is explicitly static const int ci = 1; // ci is implicitly static extern const int eci = 2; // eci is explicitly extern extern int ei = 3; // ei is explicitly extern int i = 4; // i is implicitly extern static int si = 5; // si is explicitly staticна функциональном уровне
staticозначает, что значение сохраняется между вызовами функции.
Семантика функцииstaticпеременные похожи на глобальные переменные в том, что они проживают в сегмент данных программы (а не стек или куча), см. этот вопрос подробнее оstaticвремя жизни переменных.At
classуровень
staticозначает, что значение разделяется между всеми экземплярами класса иconstозначает, что он не меняется.
Пространство Имен
// foo.h static const int i = 0;'
i' будет отображаться в каждой единице перевода, которая включает заголовок. Однако, если вы на самом деле не используете адрес объекта (например. -&i'), я почти уверен, что компилятор будет рассматривать 'i' просто как тип сейфа0. Где больше двух единицы перевода принимают '&i' тогда адрес будет отличаться для каждой единицы перевода.// foo.cc static const int i = 0;'
i' имеет внутреннюю связь, и поэтому не может быть упомянут вне этой единицы перевода. Однако, опять же, если вы не используете его адрес, он, скорее всего, будет рассматриваться как типобезопасный0.одна вещь, которую следует отметить, заключается в том, что следующее объявление:
const int i1 = 0;и ровно то же самое, что
static const int i = 0. Один переменная в пространстве имен, объявленном с помощьюconstи явно не объявлено сexternнеявно статические. Если вы подумаете об этом, то это было намерение комитета C++ разрешитьconstпеременные, которые будут объявлены в заголовочных файлах без необходимости всегдаstaticключевое слово, чтобы избежать нарушения ODR.Область Действия Класса
class A { public: static const int i = 0; };в приведенном выше примере, стандарт явно указывает, что '
iне нужно быть определены, если его адрес не требуемый. Другими словами, если вы используете только 'iкак типобезопасный 0, то компилятор не определяет его. Одно различие между версиями класса и пространства имен заключается в том, что адрес 'i' (если используется в двух или более единицах) будет одинаковым для члена класса. Где используется адрес, вы должны иметь определение для него:// a.h class A { public: static const int i = 0; }; // a.cc #include "a.h" const int A::i; // Definition so that we can take the address
- Это небольшая оптимизация пространства.
когда вы говорите
const int foo = 42;вы не определяете константу, а создаете переменную только для чтения. Компилятор достаточно умен, чтобы использовать 42 всякий раз, когда он видит foo, но он также выделит для него пространство в инициализированной области данных. Это делается потому, что, как определено, foo имеет внешнюю связь. Другой блок компиляции может сказать:
extern const int foo;
чтобы получить доступ к его значению. Это не очень хорошо практика, так как эта единица компиляции понятия не имеет, что такое значение foo. Он просто знает, что это const int и должен перезагрузить значение из памяти всякий раз, когда он используется.
Теперь, объявив, что он статичен:
static const int foo = 42;компилятор может сделать свою обычную оптимизацию, но он также может сказать: "Эй, никто за пределами этого блока компиляции не может видеть foo, и я знаю, что это всегда 42, поэтому нет необходимости выделять для него пространство."
Я должен также отметить, что в C++ предпочтительным способом предотвращения выхода имен из текущего блока компиляции является использование анонимного пространства имен:
namespace { const int foo = 42; // same as static definition above }
отсутствует 'int'. Это должно быть:
const static int foo = 42;В C и C++ он объявляет целочисленную константу с локальной областью действия файла значения 42.
почему 42? Если вы еще не знаете (и трудно поверить, что вы этого не знаете), это ссылка на ответ на жизнь, Вселенную и все остальное.
В C++,
static const int foo = 42;предпочтительный способ определения и использования констант. Т. е. используйте это, а не
#define foo 42потому что это не подрывает систему безопасности типа.
ко всем замечательным ответам я хочу добавить небольшую деталь:
Если вы пишите плагины (например, библиотеки DLL или .поэтому библиотеки должны быть загружены с помощью CAD-системы), то статический это спасатель жизни, который позволяет избежать столкновения имен, как этот:
- система САПР загружает плагин A, который имеет "const int foo = 42;" в нем.
- система загружает плагин B, который имеет "const int foo = 23;" в нем.
- в результате, плагин B будет использовать значение 42 для foo, потому что загрузчик плагинов поймет, что уже есть "foo" с внешней связью.
еще хуже: Шаг 3 может вести себя по-разному в зависимости от оптимизации компилятора, механизма загрузки плагина и т. д.
У меня была эта проблема один раз с двумя вспомогательными функциями (одно и то же имя, разное поведение) в двух плагинах. Объявление их статическими решило проблему.
Да, он скрывает переменную в модуле от других модулей. В C++ я использую его, когда мне не нужно/нужно изменить a .H файл, который вызовет ненужную перестройку других файлов. Кроме того, я поставил статический сначала:
static const int foo = 42;кроме того, в зависимости от его использования компилятор даже не выделит для него хранилище и просто "встроит" значение, в котором оно используется. Без статики компилятор не может предположить, что он не используется в другом месте и не может встроиться.
эта глобальная константа ia s видна / доступна только в модуле компиляции (.cpp file). Кстати, использование статики для этой цели не рекомендуется. Лучше использовать анонимное пространство имен и перечисление:
namespace { enum { foo = 42 }; }
сделать его частным все равно будет означать, что он появляется в заголовке. Я склонен использовать "самый слабый" способ, который работает. Смотрите эту классическую статью Скотта Мейерса:http://www.ddj.com/cpp/184401197 (речь идет о функциях, но может быть применена и здесь).
согласно спецификации C99 / GNU99:
static
спецификатор класса хранения
объекты области уровня файла по умолчанию имеет внешний связь
- объекты области уровня файла со статическим спецификатором имеет внутренние связь
const
тип-квалификатор (это часть типа)
ключевое слово применяется к непосредственному левому экземпляру-т. е.
MyObj const * myVar;- неквалифицированный указатель на тип объекта const qualified
MyObj * const myVar;константный указатель получить квалифицированный неквалифицированный тип объектакрайнее левое использование-применяется к типу объекта, а не к переменной
const MyObj * myVar;- неквалифицированный указатель на const квалифицированный объект типатаким образом:
static NSString * const myVar;- постоянный указатель на неизменяемую строку с внутренней связью.отсутствие
staticключевое слово сделает имя переменной глобальным и может привести к конфликтам имен в приложении.
Comments