Jump to content

константа (компьютерное программирование)

(Перенаправлено с Const-корректность )

В некоторых языках программирования const это квалификатор типа ( ключевое слово, применяемое к типу данных ), который указывает, что данные доступны только для чтения. Хотя это можно использовать для объявления констант , const в семействе языков C отличается от аналогичных конструкций в других языках тем, что является частью type и , таким образом, имеет сложное поведение в сочетании с указателями , ссылками, составными типами данных и проверкой типов . В других языках данные не хранятся в одной ячейке памяти , а копируются во время компиляции для каждого использования. [1] Языки, которые его используют, включают C , C++ , D , JavaScript , Julia и Rust .

Введение

[ редактировать ]

в объекта объявлении При применении [а] это указывает на то, что объект является константой : его значение нельзя изменить, в отличие от переменной . Это основное использование — объявление констант — имеет параллели во многих других языках.

Однако, в отличие от других языков, в семье языков C const является частью типа , а не частью объекта . Например, в С, int const x = 1; объявляет объект x из int const тип – const является частью типа, как если бы он был проанализирован "(int const) x" – в то время как в Ada , X : constant INTEGER := 1_ объявляет константу (разновидность объекта) X из INTEGER тип: constant является частью объекта , но не частью типа .

Это имеет два тонких результата. Во-первых, const можно применить к деталям более сложного типа – например, int const * const x; объявляет постоянный указатель на постоянное целое число, а int const * x; объявляет указатель переменной на постоянное целое число и int * const x; объявляет постоянный указатель на целочисленную переменную. Во-вторых, потому что const является частью типа, оно должно совпадать в рамках проверки типов. Например, следующий код недействителен:

void f(int& x);
// ...
int const i;
f(i);

потому что аргумент f должно быть целочисленной переменной , но i является постоянным целым числом. Это соответствие является формой корректности программы и известно как const-корректность . Это позволяет использовать форму программирования по контракту , где функции указывают в своей сигнатуре типа, изменяют ли они свои аргументы или нет, и можно ли их возвращаемое значение изменить или нет. Эта проверка типов в первую очередь представляет интерес для указателей и ссылок (не для базовых типов значений, таких как целые числа), но также для составных типов данных или шаблонных типов, таких как контейнеры . Оно скрыто тем, что const часто может быть опущен из-за приведения типов (неявное преобразование типов ) и того, что C является вызовом по значению (C++ и D — это либо вызов по значению, либо вызов по ссылке).

Последствия

[ редактировать ]

Идея константности не означает, что переменная, хранящаяся в памяти компьютера, не подлежит записи. Скорее, const-ness — это конструкция времени компиляции , которая указывает, что программисту следует делать, а не обязательно, что он может сделать. Однако обратите внимание, что в случае предопределенных данных (таких как char const * строковые литералы ), C const часто невозможно записать.

Отличие от констант

[ редактировать ]

Хотя константа не меняет своего значения во время работы программы, объявленный объект const действительно может изменить свое значение во время работы программы. Типичным примером являются регистры только для чтения во встроенных системах, такие как текущее состояние цифрового входа. Регистры данных для цифровых входов часто объявляются как const и volatile. Содержимое этих регистров может меняться без каких-либо действий со стороны программы ( volatile), но было бы неправильно, если бы программа попыталась записать в них запись ( const).

Другое использование

[ редактировать ]

Кроме того, (нестатическая) функция-член может быть объявлена ​​как const. В этом случае this указатель внутри такой функции имеет тип object_type const * а не просто типа object_type *. [2] Это означает, что неконстантные функции для этого объекта не могут быть вызваны изнутри такой функции, а переменные-члены не могут быть изменены. В C++ переменная-член может быть объявлена ​​как mutable, что указывает на то, что данное ограничение на него не распространяется. В некоторых случаях это может быть полезно, например при кэшировании , подсчете ссылок и синхронизации данных . В этих случаях логическое значение (состояние) объекта не меняется, но объект не является физически постоянным, поскольку его побитовое представление может меняться.

Синтаксис

[ редактировать ]

В C, C++ и D могут быть объявлены все типы данных, включая те, которые определены пользователем. const, а const-correctness требует, чтобы все переменные или объекты были объявлены как таковые, если их не нужно изменять. Столь активное использование const делает ценности «более понятными, отслеживаемыми и обоснованными», [3] и, таким образом, это повышает читаемость и понятность кода, а также упрощает работу в группах и поддержку кода, поскольку передает информацию о предполагаемом использовании значения. Это может помочь как компилятору , так и разработчику при обсуждении кода. Это также может позволить оптимизирующему компилятору генерировать более эффективный код. [4]

Простые типы данных

[ редактировать ]

Для простых типов данных без указателей применение const квалификатор простой. Он может идти по обе стороны от некоторых типов по историческим причинам (например, const char foo = 'a'; эквивалентно char const foo = 'a';). В некоторых реализациях использование const дважды (например, const char const или char const const) генерирует предупреждение, но не ошибку.

Указатели и ссылки

[ редактировать ]

Для типов указателей и ссылок значение const сложнее: либо сам указатель, либо значение, на которое он указывает, либо и то, и другое. const. Кроме того, синтаксис может сбивать с толку. Указатель может быть объявлен как const указатель на записываемое значение или записываемый указатель на const ценность, или const указатель на const ценить. А const Указатель нельзя переназначить, чтобы он указывал на объект, отличный от того, который ему изначально назначен, но его можно использовать для изменения значения, на которое он указывает (называемого указателем ) . [5] [6] [7] [8] [9] Ссылочные переменные в C++ представляют собой альтернативный синтаксис для const указатели. Указатель на const объект, с другой стороны, можно переназначить, чтобы он указывал на другую ячейку памяти (которая должна быть объектом того же типа или конвертируемого типа), но его нельзя использовать для изменения памяти, на которую он указывает. А const указатель на const объект также может быть объявлен и не может ни использоваться для изменения указателя, ни переназначаться для указания на другой объект. Следующий код иллюстрирует эти тонкости:

void Foo( int * ptr,
          int const * ptrToConst,
          int * const constPtr,
          int const * const constPtrToConst )
{
    *ptr = 0; // OK: modifies the pointed to data
    ptr  = NULL; // OK: modifies the pointer

    *ptrToConst = 0; // Error! Cannot modify the pointed to data
    ptrToConst  = NULL; // OK: modifies the pointer

    *constPtr = 0; // OK: modifies the pointed to data
    constPtr  = NULL; // Error! Cannot modify the pointer

    *constPtrToConst = 0; // Error! Cannot modify the pointed to data
    constPtrToConst  = NULL; // Error! Cannot modify the pointer
}

Соглашение C

[ редактировать ]

Следуя обычному соглашению C об объявлениях, объявление следует за использованием, а * в указателе пишется на указателе, обозначающем разыменование . Например, в декларации int *ptr, разыменованная форма *ptr это int, а справочная форма ptr является указателем на int. Таким образом const изменяет имя справа. Вместо этого соглашение C++ заключается в том, чтобы связать * с типом, как в int* ptrи прочитайте const как изменение типа слева. int const * ptrToConst таким образом, можно прочитать как « *ptrToConst это int const" (значение постоянное) или " ptrToConst это int const *" (указатель является указателем на постоянное целое число). Таким образом:

int *ptr;                          // *ptr is an int value
int const *ptrToConst;             // *ptrToConst is a constant (int: integer value)
int * const constPtr;              // constPtr is a constant (int *: integer pointer)
int const * const constPtrToConst; // constPtrToConst is a constant pointer and points
                                   // to a constant value

Соглашение С++

[ редактировать ]

Следуя соглашению C++, согласно которому анализируется тип, а не значение, существует практическое правило : читать объявление справа налево. Таким образом, все, что находится слева от звезды, может быть идентифицировано как заостренный тип, а все, что справа от звезды, — это свойства указателя. Например, в нашем примере выше, int const * может быть прочитан как записываемый указатель, который ссылается на недоступное для записи целое число, и int * const может быть прочитан как недоступный для записи указатель, который ссылается на записываемое целое число.

Более общее правило, которое поможет вам понять сложные объявления и определения, работает следующим образом:

  1. найдите идентификатор, объявление которого вы хотите понять
  2. читайте как можно дальше вправо (т. е. до конца объявления или до следующей закрывающей скобки, в зависимости от того, что наступит раньше)
  3. вернитесь туда, где вы начали, и прочитайте назад влево (т. е. до начала объявления или до открывающей скобки, соответствующей закрывающей скобке, найденной на предыдущем шаге)
  4. когда вы дойдете до начала объявления, все готово. Если нет, перейдите к шагу 2 за закрывающей скобкой, которая была сопоставлена ​​последней.

Вот пример:

Часть выражения
double (**const (*fun(int))(double))[10]
Значение
(читаем вниз)
Идентификатор
                  fun
fun - это...
Читать направо
                     (int))
функция, ожидающая int...
Найдите совпадение (
                (*
возврат указателя на...
Продолжайте двигаться правильно
                           (double))
функция, ожидающая двойного значения...
Найдите совпадение (
        (**const
возвращение постоянного указателя на
указатель на...
Продолжайте двигаться правильно
                                    [10]
блоки по 10...
Читать слева
double
удваивается.

При чтении налево важно читать элементы справа налево. Итак, int const * становится указателем на const int , а не константным указателем на int .

В некоторых случаях C/C++ позволяет const ключевое слово, которое будет размещено слева от типа. Вот несколько примеров:

const int *ptrToConst;            //identical to: int const *ptrToConst,
const int *const constPtrToConst; //identical to: int const *const constPtrToConst

Хотя C/C++ допускает такие определения (которые близко соответствуют английскому языку при чтении определений слева направо), компилятор все равно читает определения в соответствии с вышеупомянутой процедурой: справа налево. Но положив const прежде чем то, что должно быть постоянным, быстро приведет к несоответствию между тем, что вы собираетесь написать, и тем, что компилятор решит, что вы написали. Рассмотрим указатели на указатели:

int **ptr;            // a pointer to a pointer to ints
int const **ptr       // a pointer to a pointer to constant int value
                      // (not a pointer to a constant pointer to ints)
int *const *ptr       // a pointer to a const pointer to int values
                      // (not a constant pointer to a pointer to ints)
int **const ptr       // a constant pointer to pointers to ints
                      // (ptr, the identifier, being const makes no sense)
int const **const ptr // a constant pointer to pointers to constant int values

И последнее замечание относительно определений указателей: всегда пишите символ указателя (*) как можно правее. Присоединить символ указателя к типу сложно, поскольку он явно предполагает тип указателя, а это не так. Вот несколько примеров:

int* a;          /* write: */     int *a;    // a is a pointer to an int
int* a, b;       // CONFUSING 
                 /* write: */     int *a, b; // a is a pointer to an int, 
                 //                             but b is a mere int
int* a, *b;      // UGLY: both a and b are pointers to ints
                 /* write: */     int *a, *b;

Во избежание этой проблемы в FAQ Бьёрна Страуструпа при использовании соглашения C++ рекомендуется объявлять только одну переменную в строке. [10]

Те же соображения применимы к определению ссылок и ссылок rvalue:

int var = 22;
int const &refToConst = var;         // OK
int const& ref2 = var, ref3 = var;   // CONFUSING:
                                     // ref2 is a reference, but ref3 isn't:
                                     // ref3 is a constant int initialized with
                                     // var's value
int &const constRef = var;           // ERROR: as references can't change anyway.

// C++:
int&& rref = int(5), value = 10;     // CONFUSING:
                                     // rref is an rvalue reference, but value is
                                     // a mere int. 
                                     /* write: */ int &&rref = int(5), value = 10;

Более сложные объявления встречаются при использовании многомерных массивов и ссылок (или указателей) на указатели. Хотя иногда утверждают [ ВОЗ? ] Поскольку такие объявления сбивают с толку и подвержены ошибкам, и поэтому их следует избегать или заменять структурами более высокого уровня, процедуру, описанную в начале этого раздела, всегда можно использовать, не внося двусмысленности или путаницы.

Параметры и переменные

[ редактировать ]

const может быть объявлен как для параметров функции, так и для переменных ( статических или автоматических, включая глобальные или локальные). Интерпретация варьируется в зависимости от использования. А const статическая переменная (глобальная переменная или статическая локальная переменная) является константой и может использоваться для таких данных, как математические константы, такие как double const PI = 3.14159 – реально более длинные или общие параметры времени компиляции. А const автоматическая переменная (нестатическая локальная переменная) означает, что происходит одно присвоение , хотя каждый раз может использоваться другое значение, например int const x_squared = x * x. А const параметр при передаче по ссылке означает, что указанное значение не изменяется – оно является частью контракта – в то время как const параметр при передаче по значению (или сам указатель при передаче по ссылке) ничего не добавляет к интерфейсу (поскольку значение было скопировано), но указывает, что внутри функция не изменяет локальную копию параметр (это одно присвоение). По этой причине некоторые предпочитают использовать const в параметрах только для передачи по ссылке, где он меняет контракт, но не для передачи по значению, где он предоставляет реализацию.

Чтобы воспользоваться преимуществами подхода проектирования по контракту для определяемых пользователем типов (структур и классов), которые могут иметь как методы, так и данные-члены, программист может помечать методы экземпляра как const если они не изменяют элементы данных объекта. Применение const Таким образом, квалификатор экземпляра метода является важной функцией для const-корректности и недоступен во многих других объектно-ориентированных языках, таких как Java и C# , а также в Microsoft или C++/CLI Managed Extensions for C++ . Пока const методы могут вызываться const и не- const объекты одинаковые, не const методы могут быть вызваны только не- const объекты. const модификатор метода экземпляра применяется к объекту, на который указывает " this" указатель, который является неявным аргументом, передаваемым всем методам экземпляра. Таким образом, имея const методы — это способ применить константную корректность к неявным " this"аргумент-указатель, как и другие аргументы.

Этот пример иллюстрирует:

class C
{
    int i;
public:
    int Get() const // Note the "const" tag
      { return i; }
    void Set(int j) // Note the lack of "const"
      { i = j; }
};

void Foo(C& nonConstC, C const& constC)
{
    int y = nonConstC.Get(); // Ok
    int x = constC.Get();    // Ok: Get() is const

    nonConstC.Set(10); // Ok: nonConstC is modifiable
    constC.Set(10);    // Error! Set() is a non-const method and constC is a const-qualified object
}

В приведенном выше коде неявное " this"указатель на Set() имеет тип " C *const"; тогда как " this"указатель на Get() имеет тип " C const *const", что указывает на то, что метод не может изменить свой объект через " this"указатель.

Часто программист предоставляет как const и не- const метод с тем же именем (но, возможно, с совершенно разным использованием) в классе, подходящий для обоих типов вызывающих объектов. Учитывать:

class MyArray
{
    int data[100];
public:
    int &       Get(int i)       { return data[i]; }
    int const & Get(int i) const { return data[i]; }
};

void Foo( MyArray & array, MyArray const & constArray )
{
    // Get a reference to an array element
    // and modify its referenced value.

    array.Get( 5 )      = 42; // OK! (Calls: int & MyArray::Get(int))
    constArray.Get( 5 ) = 42; // Error! (Calls: int const & MyArray::Get(int) const)
}

The const-ness вызывающего объекта определяет, какая версия MyArray::Get() будет вызван и, следовательно, будет ли вызывающему объекту предоставлена ​​ссылка, с помощью которой он может манипулировать или только наблюдать за частными данными в объекте. Технически эти два метода имеют разные сигнатуры, поскольку их " this" Указатели имеют разные типы, что позволяет компилятору выбрать правильный. (Возврат const ссылка на int, вместо того, чтобы просто возвращать int по значению, во втором методе это может быть излишним, но для произвольных типов можно использовать тот же метод, что и в стандартной библиотеке шаблонов .)

Лазейки в константной корректности

[ редактировать ]

В C и C++ есть несколько лазеек для чистой константной корректности. Они существуют в первую очередь для совместимости с существующим кодом.

Первый, применимый только к C++, — это использование const_cast, что позволяет программисту удалить const квалификатор, делающий любой объект модифицируемым. Необходимость удаления квалификатора возникает при использовании существующего кода и библиотек, которые нельзя изменить, но которые не являются константно-корректными. Например, рассмотрим этот код:

// Prototype for a function which we cannot change but which
// we know does not modify the pointee passed in.
void LibraryFunc(int* ptr, int size);

void CallLibraryFunc(int const * ptr, int size)
{
    LibraryFunc(ptr, size); // Error! Drops const qualifier

    int* nonConstPtr = const_cast<int*>(ptr); // Strip qualifier
    LibraryFunc(nonConstPtr, size);  // OK
}

Однако любая попытка изменить объект, который сам объявлен const с помощью приведения const приводит к неопределенному поведению в соответствии со стандартом ISO C++. В приведенном выше примере, если ptr ссылается на глобальную, локальную переменную или переменную-член, объявленную как constили объект, выделенный в куче через new int const, код корректен только в том случае, если LibraryFunc действительно не изменяет значение, на которое указывает ptr.

Языку C нужна лазейка, потому что существует определенная ситуация. Переменным со статическим сроком хранения разрешено определять начальное значение. Однако инициализатор может использовать только константы, такие как строковые константы и другие литералы, и ему не разрешено использовать непостоянные элементы, такие как имена переменных, независимо от того, объявлены ли элементы инициализатора. const или нет, или объявляется ли статическая переменная продолжительности const или нет. Существует непереносимый способ инициализации const переменная, имеющая статическую продолжительность хранения. Тщательно создав приведение типа в левой части более позднего задания, const в переменную можно записать, эффективно удаляя const атрибут и «инициализировать» его непостоянными элементами, такими как другие const переменные и тому подобное. Запись в const переменная таким образом может работать по назначению, но вызывает неопределенное поведение и серьезно противоречит константной корректности:

size_t const    bufferSize = 8*1024;
size_t const    userTextBufferSize;  //initial value depends on const bufferSize, can't be initialized here

...

int setupUserTextBox(textBox_t *defaultTextBoxType, rect_t *defaultTextBoxLocation)
{
    *(size_t*)&userTextBufferSize = bufferSize - sizeof(struct textBoxControls);  // warning: might work, but not guaranteed by C
    ...
}

Еще одна лазейка [11] применимо как к C, так и к C++. В частности, языки требуют, чтобы указатели и ссылки на члены были «поверхностными» по отношению к const-ность их владельцев – то есть вмещающий объект, который const есть все const членов, за исключением того, что члены-поинты (и рецензенты) по-прежнему изменчивы. Для иллюстрации рассмотрим следующий код C++:

struct S
{
    int val;
    int *ptr;
};

void Foo(S const & s)
{
    int i  = 42;
    s.val  = i;  // Error: s is const, so val is a const int
    s.ptr  = &i; // Error: s is const, so ptr is a const pointer to int
    *s.ptr = i;  // OK: the data pointed to by ptr is always mutable,
                 //     even though this is sometimes not desirable
}

Хотя объект s перешел к Foo() является константой, что делает все ее члены постоянными, а указатель доступен через s.ptr все еще поддается модификации, хотя это может быть нежелательно с точки зрения const-правильность, потому что s может единолично владеть пуантом. По этой причине Мейерс утверждает, что указатели и ссылки на члены по умолчанию должны быть «глубокими». const-ность, которая может быть преодолена mutable квалификатор, когда указатель не принадлежит контейнеру, но эта стратегия создаст проблемы совместимости с существующим кодом. Таким образом, по историческим причинам [ нужна ссылка ] , эта лазейка остается открытой в C и C++.

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

Наконец, несколько функций стандартной библиотеки C нарушают const-корректность до C23 , поскольку они принимают const указатель на строку символов и вернуть не- const указатель на часть той же строки. strstr и strchr входят в число этих функций. Некоторые реализации стандартной библиотеки C++, например Microsoft. [12] попробуйте закрыть эту лазейку, предоставив две перегруженные версии некоторых функций: " const"версия и "не- const"Версия.

Проблемы

[ редактировать ]

Использование системы типов для выражения постоянства приводит к различным сложностям и проблемам и, соответственно, подвергается критике и не принимается за пределами узкого семейства C, состоящего из C, C++ и D. Java и C#, на которые сильно влияют C и C++, оба явно отвергнуты constквалификаторы типа -style, вместо того, чтобы выражать постоянство с помощью ключевых слов, которые применяются к идентификатору ( final на Яве, const и readonly в С#). Даже в C и C++ использование const значительно различается: некоторые проекты и организации используют его постоянно, а другие избегают.

strchr проблема

[ редактировать ]

The const Квалификатор типа вызывает трудности, когда логика функции не зависит от того, является ли ее ввод константой или нет, но возвращает значение, которое должно быть того же квалифицированного типа, что и ввод. Другими словами, для этих функций, если входные данные являются константами (с константами), возвращаемое значение также должно быть, но если входные данные являются переменными (не const-qualified), возвращаемое значение также должно быть. Поскольку сигнатуры типов этих функций различаются, для этого требуются две функции (или, возможно, больше, в случае нескольких входных данных) с одинаковой логикой — форма универсального программирования .

Эта проблема возникает даже для простых функций стандартной библиотеки C, особенно strchr; это наблюдение Ричи приписывает Тому Пламу в середине 1980-х годов. [13] strchr функция находит символ в строке; формально он возвращает указатель на первое появление символа c в строке s, а в классическом C (K&R C) его прототипом является:

char *strchr(char *s, int c);

The strchr функция не изменяет входную строку, но возвращаемое значение часто используется вызывающей стороной для изменения строки, например:

if (p = strchr(q, '/'))
    *p = ' ';

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

В C++ это делается посредством перегрузки функций , обычно реализуемой через шаблон , в результате чего создаются две функции, так что возвращаемое значение имеет одинаковое значение. const-квалифицированный тип в качестве входных данных: [б]

char* strchr(char* s, int c);
char const* strchr(char const* s, int c);

Они, в свою очередь, могут быть определены с помощью шаблона:

template <T>
T* strchr(T* s, int c) { ... }

В D это осуществляется через inout Ключевое слово, которое действует как подстановочный знак для константы, неизменяемости или неквалифицированной (переменной), что дает: [14] [с]

inout(char)* strchr(inout(char)* s, int c);

Однако в C ни один из этих вариантов невозможен, поскольку C не имеет перегрузки функций, и вместо этого это решается с помощью одной функции, где входные данные постоянны, а выходные данные доступны для записи:

char *strchr(char const *s, int c);

Это позволяет использовать идиоматический код C, но удаляет квалификатор const, если входные данные действительно были квалифицированы как const, что нарушает безопасность типов. Это решение было предложено Ритчи и впоследствии принято. Это различие является одним из недостатков совместимости C и C++ .

Начиная с C23 , эта проблема решается с использованием универсальных функций. strchr и другие функции, затронутые этой проблемой, вернут const указатель, если он был им передан, и неквалифицированный указатель, если им был передан неквалифицированный указатель. [15]

В версии 2 языка программирования D существуют два ключевых слова, относящиеся к const. [16] immutable Ключевое слово обозначает данные, которые не могут быть изменены посредством какой-либо ссылки. const Ключевое слово обозначает неизменяемое представление изменяемых данных. В отличие от С++ const, Д const и immutable являются «глубокими» или транзитивными , и все, что достижимо через const или immutable объект const или immutable соответственно.

Пример константы и неизменности в D

int[] foo = new int[5];  // foo is mutable.
const int[] bar = foo;   // bar is a const view of mutable data.
immutable int[] baz = foo;  // Error:  all views of immutable data must be immutable.

immutable int[] nums = new immutable(int)[5];  // No mutable reference to nums may be created.
const int[] constNums = nums;  // Works.  immutable is implicitly convertible to const.
int[] mutableNums = nums;  // Error:  Cannot create a mutable view of immutable data.

Пример транзитивной или глубокой константы в D

class Foo {
    Foo next;
    int num;
}

immutable Foo foo = new immutable(Foo);
foo.next.num = 5;  // Won't compile.  foo.next is of type immutable(Foo).
                   // foo.next.num is of type immutable(int).

const был представлен Бьярном Страуструпом в C with Classes , предшественнике C++ , в 1981 году и первоначально назывался readonly. [17] [18] Что касается мотивации, Страуструп пишет: [18]

«Он выполнял две функции: как способ определения символической константы, которая подчиняется правилам области видимости и типа (то есть без использования макроса), и как способ считать объект в памяти неизменяемым».

Первое использование в качестве ограниченной и типизированной альтернативы макросам было аналогично выполнено для функциональных макросов через метод inline ключевое слово. Постоянные указатели и * const обозначения были предложены Деннисом Ритчи и приняты. [18]

const затем был принят в C как часть стандартизации и появляется в C89 (и последующих версиях) вместе с другим квалификатором типа, volatile. [19] Еще один квалификатор, noalias, было предложено на заседании комитета X3J11 в декабре 1987 года, но было отклонено; ее цель была в конечном итоге достигнута restrict ключевое слово в C99 . Ричи не очень поддержал эти дополнения, утверждая, что они «не несут своего веса», но в конечном итоге не выступал за их удаление из стандарта. [20]

D впоследствии унаследовал const из C++, где он известен как конструктор типа (а не квалификатор типа ), и добавлены еще два конструктора типа, immutable и inout, для обработки связанных случаев использования. [д]

Другие языки

[ редактировать ]

Другие языки не следуют C/C++ в части константности типа, хотя они часто имеют внешне похожие конструкции и могут использовать const ключевое слово. Обычно это используется только для констант (постоянных объектов).

В C# есть const Ключевое слово, но с радикально другой и более простой семантикой: оно означает константу времени компиляции и не является частью типа.

У Нима есть const Ключевое слово аналогично ключевому слову C#: оно также объявляет константу времени компиляции, а не является частью типа. Однако в Nim константу можно объявить из любого выражения, которое можно вычислить во время компиляции. [21] В C# только встроенные типы C# могут быть объявлены как const; определяемые пользователем типы, включая классы, структуры и массивы, не могут быть const. [22]

Явы нет const - вместо этого он имеет final, который может применяться к объявлениям локальных «переменных» и применяется к идентификатору , а не к типу. Он имеет другое объектно-ориентированное использование членов объекта, что и является источником названия.

Спецификация языка Java касается const как зарезервированное ключевое слово, т. е. такое, которое нельзя использовать в качестве идентификатора переменной, но которое не придает ему никакой семантики: это зарезервированное слово (оно не может использоваться в идентификаторах), но не ключевое слово (оно не имеет специального значения). Это ключевое слово было включено в качестве средства, позволяющего компиляторам Java обнаруживать и предупреждать о неправильном использовании ключевых слов C++. [23] Билет запроса на улучшение для реализации const Корректность существует в процессе сообщества Java , но была закрыта в 2005 году на том основании, что ее невозможно реализовать с помощью обратной совместимости. [24]

Современная Ада 83 независимо имела понятие постоянного объекта и constant ключевое слово, [25] [и] при этом входные параметры и параметры цикла неявно постоянны. Здесь constant является свойством объекта, а не типа.

В JavaScript есть const объявление, определяющее переменную в области блока , которую нельзя ни переназначить, ни переобъявить. Он определяет ссылку на переменную, доступную только для чтения, которую нельзя переопределить, но в некоторых ситуациях значение самой переменной потенциально может измениться, например, если переменная ссылается на объект и изменяется его свойство. [26]

См. также

[ редактировать ]

Примечания

[ редактировать ]
  1. ^ Формально, когда const является частью самого внешнего производного типа в объявлении; указатели усложняют обсуждение.
  2. ^ Обратите внимание, что правила синтаксиса объявления указателей различаются в C и C++: в C char *s является стандартным, а в C++ char* s является стандартным.
  3. ^ Идиоматический код D здесь будет использовать массив вместо указателя. [14]
  4. ^ D также представил shared конструктор типа, но это связано со случаями использования volatile, нет const.
  5. ^ В стандарте Ada это называется « зарезервированным словом »; см. эту статью для использования.
  1. ^ «Постоянные предметы – Справочник по ржавчине» . doc.rust-lang.org . Проверено 22 июня 2022 г.
  2. ^ " this указатель» . Черновик стандарта C++ . Проверено 30 марта 2020 г .. Тип this в функции-члене, тип которой имеет cv-qualifier-seq cv и чей класс X это «указатель на резюме X".
  3. ^ Херб Саттер и Андрей Александреску (2005). Стандарты кодирования C++ . п. 30. Бостон: Эддисон Уэсли. ISBN   0-321-11358-6
  4. ^ «Почему аргумент kfree() является константным?» . lkml.org. 12 января 2013 г.
  5. ^ «5.1. Расширения, реализованные в GNU Fortran: 5.1.16 Указатели Cray». Компилятор GNU Fortran . 2006. Архивировано из оригинала 21 декабря 2022 г. Проверено 21 декабря 2022 г.
  6. ^ Фэйи, Марк Р.; Нэгл, Дэн (19 апреля 1999 г.). «Указатели Cray Fortran против указателей Fortran 90 и перенос с Cray C90 на SGI Origin2000» (PDF) . Виксбург, Массачусетс, США: Экспериментальная станция водных путей Инженерного корпуса армии США, Главный центр общих ресурсов. Архивировано (PDF) из оригинала 23 декабря 2022 г. Проверено 23 декабря 2022 г. (8 страниц)
  7. ^ «Приложение C: Особенности и различия Fortran 90 > Возможности > Указатели Cray» . Руководство пользователя Фортрана . Корпорация Оракл . 2010. Архивировано из оригинала 21 сентября 2021 г. Проверено 23 декабря 2022 г.
  8. ^ «Приложение C: Особенности и различия Fortran 90 > Возможности > Указатели символов Cray» . Руководство пользователя Фортрана . Корпорация Оракл . 2010. Архивировано из оригинала 23 декабря 2022 г. Проверено 23 декабря 2022 г.
  9. ^ «Глава 4. Типы данных». Справочное руководство по языку Фортран, Том 1 . Том. 1. Silicon Graphics, Inc. 1999 [1993]. Номер документа: 007-3692-004. Архивировано из оригинала 23 декабря 2022 г. Проверено 23 декабря 2022 г. (Примечание. Взято из «РУКОВОДСТВА ПО FORTRAN 90» (1992, McGraw-Hill, Inc. ) Уолтера С. Брейнерда, Джин К. Адамс, Джин Т. Мартин, Брайана Т. Смита и Джерролда Л. Вагенера.)
  10. ^ «Страуструп: Часто задаваемые вопросы по стилю и технике C++» .
  11. ^ Скотт Мейерс (2005). Эффективный C++, третье издание . стр. 21–23. Бостон: Эддисон Уэсли. ISBN   978-0-321-33487-9
  12. ^ "strchr, wcschr, _mbschr (CRT)" . Msdn.microsoft.com . Проверено 23 ноября 2017 г.
  13. ^ «Деннис Ритчи: Почему мне не нравятся квалификаторы типа X3J11» .
  14. ^ Jump up to: а б Язык программирования D, Андрей Александреску , 8.8: Передача квалификатора от параметра к результату
  15. ^ «WG14-N3020: Функции стандартной библиотеки, сохраняющие квалификаторы» (PDF) . open-std.org . 13.06.2022. Архивировано (PDF) из оригинала 13 октября 2022 г.
  16. ^ «const(FAQ) – язык программирования D» . Digitalmars.com . Проверено 18 августа 2013 г.
  17. ^ Бьерн Страуструп , «Расширения концепции типа языка C», внутренний технический меморандум Bell Labs, 5 января 1981 г.
  18. ^ Jump up to: а б с Соперничество между братьями и сестрами: C и C++ , Бьёрн Страуструп , 2002, стр. 5
  19. ^ Деннис М. Ритчи , « Развитие языка C. Архивировано 15 июля 2012 г., archive.today », 2003 г.: «X3J11 также внес множество мелких дополнений и корректировок, например, квалификаторы типа const и voluty и немного другие правила продвижения по типу».
  20. ^ «Позвольте мне начать с того, что я не уверен, что даже квалификаторы до декабря («const» и «летучие») имеют свой вес; я подозреваю, что то, что они добавляют к стоимости изучения и использования языка, не является отплатил большей выразительностью. «Неустойчивость», в частности, является дополнением к эзотерическим приложениям и гораздо лучше выражается другими средствами. Его главное достоинство в том, что почти каждый может о нем забыть. «Const» одновременно более полезен и более навязчив; вы не можете не узнать об этом из-за его присутствия в интерфейсе библиотеки. Тем не менее, я не выступаю за отмену квалификаций хотя бы потому, что уже слишком поздно».
  21. ^ Руководство Nim: раздел Const
  22. ^ const (Справочник по C#)
  23. ^ Гослинг, Джеймс; Джой, Билл; Стил, Гай. «Спецификация языка Java, третье издание» .
  24. ^ «Идентификатор ошибки: JDK-4211070 Java должна поддерживать константные параметры (например, C++) для поддержки кода [ sic . Bugs.sun.com . Проверено 4 ноября 2014 г.
  25. ^ 1815А [ мертвая ссылка ] , 3.2.1. Объявления объектов. Архивировано 20 октября 2014 г. в Wayback Machine :
    «Объявленный объект является константой, если в объявлении объекта появляется зарезервированное слово константа; тогда объявление должно включать явную инициализацию. Значение константы не может быть изменено после инициализации. Формальные параметры режима в подпрограммах и записях, а также общие параметры формальные параметры режима in также являются константами; параметр цикла является константой внутри соответствующего цикла; подкомпонент или фрагмент константы является константой.
  26. ^ «константа» . МДН . Проверено 31 октября 2017 г.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 8013fc087edbda6cd208bc8e3446ee36__1721232780
URL1:https://arc.ask3.ru/arc/aa/80/36/8013fc087edbda6cd208bc8e3446ee36.html
Заголовок, (Title) документа по адресу, URL1:
const (computer programming) - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)