Что означает "const static" в C и c++?



const static int foo = 42;


Я видел это в каком-то коде здесь, на StackOverflow, и я не мог понять, что он делает. Затем я увидел некоторые путаные ответы на других форумах. Мое лучшее предположение, что он используется в C, чтобы скрыть константу foo из других модулей. Это правильно? Если да, то зачем кому-то использовать его в контексте C++, где вы можете просто сделать это private?

1517   11  
c

11 ответов:

Он имеет использование как в C, так и в C++.

как вы догадались,static часть ограничивает свою область действия этим единица компиляции. Он также обеспечивает статическую инициализацию. const просто говорит компилятору не позволять никому изменять его. Эта переменная либо помещается в сегмент data, либо BSS в зависимости от архитектуры, и может быть помечена в памяти только для чтения.

все это то, как C обрабатывает эти переменные (или как C++ обрабатывает переменные пространства имен). В C++ член с пометкой static является общим для всех экземпляров данного класса. Является ли она частной или нет, не влияет на то, что одна переменная совместно используется несколькими экземплярами. Имея const on там предупредит вас, если какой-либо код попытается изменить это.

если бы он был строго частным, то каждый экземпляр класса получил бы свою собственную версию (несмотря на оптимизатор).

много людей дали ответ, но никто не указал, что в C++ const по умолчанию static at namespace уровень (и некоторые дали неверную информацию). Увидеть стандарта 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-системы), то статический это спасатель жизни, который позволяет избежать столкновения имен, как этот:

  1. система САПР загружает плагин A, который имеет "const int foo = 42;" в нем.
  2. система загружает плагин B, который имеет "const int foo = 23;" в нем.
  3. в результате, плагин 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

    Ничего не найдено.