Константа (компьютерное программирование)
В компьютерном программировании константа значение — это , которое не изменяется программой во время нормального выполнения . Когда константа связана с идентификатором , ее называют «именованной», хотя термины «константа» и «именованная константа» часто используются как синонимы. Это контрастирует с переменной , которая представляет собой идентификатор со значением, которое можно изменить во время обычного выполнения. Для упрощения: значения констант остаются, а значения переменных меняются, отсюда и их названия.
Константы полезны как для программистов, так и для компиляторов : для программистов они представляют собой форму самодокументируемого кода и позволяют рассуждать о корректности , тогда как для компиляторов они позволяют проводить проверки во время компиляции и во время выполнения , которые проверяют, что предположения о постоянстве не нарушаются. [а] и разрешить или упростить некоторые оптимизации компилятора .
Существуют различные конкретные реализации общего понятия константы с тонкими различиями, которые часто упускаются из виду. Наиболее значимыми являются: константы времени компиляции (статические значения), константы времени выполнения (динамические значения), неизменяемые объекты и типы констант ( const
).
Типичные примеры констант времени компиляции включают математические константы, значения из стандартов (здесь максимальная единица передачи ) или значения внутренней конфигурации (здесь количество символов в строке ), например следующие примеры на языке C :
const float PI = 3.1415927; // maximal single float precision
const unsigned int MTU = 1500; // Ethernet v2, RFC 894
const unsigned int COLUMNS = 80;
Типичными примерами констант времени выполнения являются значения, рассчитанные на основе входных данных функции, например этот C++ пример :
void f(std::string s) {
const size_t l = s.length();
// ...
}
Использовать
[ редактировать ]Некоторые языки программирования проводят явное синтаксическое различие между постоянными и переменными символами, например, считая присвоение константы синтаксической ошибкой, в то время как в других языках они считаются синтаксически одинаковыми (оба - просто идентификатор), и разница в обработке семантический (присвоение идентификатору синтаксически допустимо, но если идентификатор является константой, оно семантически недействительно).
Постоянное значение определяется один раз, и на него можно ссылаться много раз в программе. Использование константы вместо многократного указания одного и того же значения может упростить обслуживание кода (например, « не повторяться ») и самодокументироваться, предоставляя значимое имя для значения, например: PI
вместо 3.1415926.
Сравнение с литералами и макросами
[ редактировать ]Существует несколько основных способов выражения значения данных, которое не меняется во время выполнения программы, которые одинаковы для самых разных языков программирования. Один из самых простых способов — просто записать буквальное число, символ или строку в программный код, что легко сделать на C, C++ и подобных языках.
На языке ассемблера буквенные числа и символы выполняются с использованием инструкций «немедленного режима», доступных на большинстве микропроцессоров. Название «немедленный» происходит от того, что значения доступны немедленно из потока команд , а не загружаются косвенно путем поиска адреса памяти. [1] С другой стороны, значения, превышающие длину слова микропроцессора, такие как строки и массивы, обрабатываются косвенно, и ассемблеры обычно предоставляют псевдооперацию «данных» для встраивания таких таблиц данных в программу.
Другой способ — определить символический макрос . Многие языки программирования высокого уровня и многие ассемблеры предлагают макросы, с помощью которых программист может определить, обычно в начале исходного файла или в отдельном файле определений, имена для различных значений. Затем препроцессор заменяет эти имена соответствующими значениями перед компиляцией, в результате чего получается нечто функционально идентичное использованию литералов, с преимуществами скорости немедленного режима. Поскольку может быть сложно поддерживать код, в котором все значения записаны буквально, если значение используется каким-либо повторяющимся или неочевидным образом, ему часто присваивается имя макроса.
Третий способ — объявить и определить переменную как «постоянную». или Глобальную переменную статическую переменную можно объявить (или символ, определенный в ассемблере) с помощью квалификатора ключевого слова, например const
, constant
, или final
, что означает, что его значение будет установлено во время компиляции и не должно быть изменено во время выполнения. Компиляторы обычно помещают статические константы в текстовый раздел объектного файла вместе с самим кодом, в отличие от раздела данных, где хранятся неконстантные инициализированные данные. Некоторые компиляторы могут создавать раздел, специально посвященный константам. К этой области можно применить защиту памяти, чтобы предотвратить перезапись таких констант ошибочными указателями.
Эти константы отличаются от литералов по ряду причин. Компиляторы обычно помещают константу в одну ячейку памяти, определяемую символом, а не распределяют ее по всему исполняемому файлу, как в случае с макросом. Хотя это исключает преимущества в скорости немедленного режима, есть преимущества в эффективности использования памяти, и отладчики могут работать с этими константами во время выполнения. Кроме того, хотя макросы могут быть случайно переопределены из-за конфликта заголовочных файлов в C и C++, конфликтующие константы обнаруживаются во время компиляции.
В зависимости от языка константы могут быть нетипизированными или типизированными. В C и C++ макросы обеспечивают первое, тогда как const
обеспечивает последнее:
#define PI 3.1415926535
const float pi2 = 3.1415926535;
в то время как в Ada существуют универсальные числовые типы, которые при желании можно использовать:
pi : constant := 3.1415926535;
pi2 : constant float := 3.1415926535;
при этом нетипизированный вариант неявно преобразуется в соответствующий тип при каждом использовании. [2]
Динамические константы
[ редактировать ]Помимо статических констант , описанных выше, многие процедурные языки, такие как Ada и C++, расширяют концепцию константности на глобальные переменные, которые создаются во время инициализации, локальные переменные, которые автоматически создаются во время выполнения в стеке или в регистрах, на динамически выделяемую память, которая доступ осуществляется по указателю, а также к спискам параметров в заголовках функций.
Константы с динамическим значением не обозначают переменную как находящуюся в определенной области памяти, а значения не устанавливаются во время компиляции. В коде C++, таком как
float func(const float ANYTHING) {
const float XYZ = someGlobalVariable*someOtherFunction(ANYTHING);
...
}
выражение, которым инициализируется константа, само по себе не является константой. Использование константности здесь не обязательно для легальности программы или семантической корректности, но имеет три преимущества:
- Читателю ясно, что объект не будет далее модифицироваться после установки
- Попытки изменить значение объекта (со стороны более поздних программистов, не до конца понимающих логику программы) будут отклонены компилятором.
- Компилятор может выполнить оптимизацию кода, зная, что значение объекта не изменится после создания. [3]
Константы с динамическим значением возникли как функция языка АЛГОЛ 68 . [3] Исследования кода Ada и C++ показали, что константы с динамическим значением используются нечасто, обычно для 1% или меньше объектов, хотя их можно было бы использовать гораздо больше, поскольку около 40–50% локальных, неклассовых объектов фактически однажды остаются инвариантными. созданный. [3] [4] С другой стороны, такие «неизменяемые переменные», как правило, используются по умолчанию в функциональных языках, поскольку они отдают предпочтение стилям программирования без побочных эффектов (например, рекурсии) или делают большинство объявлений неизменяемыми по умолчанию, например ML . Чисто функциональные языки даже полностью запрещают побочные эффекты.
Константность часто используется в объявлениях функций как обещание того, что при передаче объекта по ссылке вызываемая функция не изменит его. В зависимости от синтаксиса константой может быть либо указатель, либо объект, на который он указывает, однако обычно желательно последнее. Особенно в C++ и C дисциплина, обеспечивающая постоянство правильных структур данных во всей программе, называется const-корректностью .
Постоянные параметры функции
[ редактировать ]В C/C++ можно объявить параметр функции или метода как константу. Это гарантия того, что этот параметр не может быть случайно изменен после его инициализации вызывающей стороной. Если параметр имеет предопределенный (встроенный) тип, он вызывается по значению и не может быть изменен. Если это пользовательский тип, переменная представляет собой адрес указателя, который также нельзя изменить. Однако содержимое объекта можно изменять без ограничений. Объявление параметров как констант может быть способом указать, что это значение не следует изменять, но программист должен иметь в виду, что компилятор не может выполнить проверку модификации объекта.
Помимо этой возможности, в C++ также можно объявить функцию или метод как const
. Это не позволяет таким функциям или методам изменять что-либо, кроме локальных переменных.
В C# ключевое слово const
существует, но не оказывает такого же эффекта на параметры функции, как в C/C++. Однако есть способ «заставить» компилятор выполнить проверку, хотя это и немного сложно. [5]
Объектно-ориентированные константы
[ редактировать ]Постоянная структура данных или объект на объектно-ориентированном языке называется « неизменяемой ». Неизменяемость объекта дает некоторые преимущества при разработке программ. Например, его можно «скопировать», просто скопировав его указатель или ссылку, избегая трудоемкой операции копирования и сохраняя память.
Объектно-ориентированные языки, такие как C++, еще больше расширяют константность. Отдельные члены структуры или класса могут быть объявлены константными, даже если класс не является константой. И наоборот, mutable
Ключевое слово позволяет изменить член класса, даже если объект был создан как const
.
Даже функции могут быть константными в C++. Смысл здесь в том, что для объекта, созданного как const, может быть вызвана только константная функция; константная функция не меняет неизменяемые данные.
В C# есть оба const
и readonly
квалификатор; его const предназначен только для констант времени компиляции, тогда как readonly можно использовать в конструкторах и других приложениях времени выполнения.
Ява
[ редактировать ]В Java есть квалификатор под названием final
это предотвращает изменение ссылки и гарантирует, что она никогда не будет указывать на другой объект. Это не предотвращает внесение изменений в сам указанный объект. Java final
в основном эквивалентен const
указатель в C++. Он не обеспечивает других функций const
.
В Java квалификатор final
утверждает, что затронутый элемент данных или переменная не может быть назначен, как показано ниже:
final int i = 3;
i = 4; // Error! Cannot modify a "final" object
Это должно быть разрешимо компиляторами, где переменная с final
маркер инициализируется и должен выполняться только один раз, иначе класс не скомпилируется. Java final
и C++ const
Ключевые слова имеют то же значение, когда применяются с примитивными переменными.
const int i = 3; // C++ declaration
i = 4; // Error!
Учитывая указатели, final
ссылка в Java означает что-то похожее на const
указатель в C++. В C++ можно объявить «тип постоянного указателя».
Foo *const bar = mem_location; // const pointer type
Здесь, bar
должен быть инициализирован во время объявления и не может быть изменен снова, но то, что он указывает, можно изменить. Т.е. *bar = value
действителен. Он просто не может указывать на другое место. Конечные ссылки в Java работают таким же образом, за исключением того, что их можно объявить неинициализированными.
final Foo i; // a Java declaration
Примечание. Java не поддерживает указатели. [6] Это связано с тем, что указатели (с ограничениями) являются способом доступа к объектам в Java по умолчанию, а Java не использует звездочки для их обозначения. Например, i в последнем примере является указателем и может использоваться для доступа к экземпляру.
В C++ также можно объявить указатель на данные «только для чтения».
const Foo *bar;
Здесь bar
можно изменить, чтобы указать что угодно и когда угодно; просто это указанное значение нельзя изменить с помощью bar
указатель.
В Java нет эквивалентного механизма. Таким образом, также нет const
методы.
Константная корректность не может быть обеспечена в Java, хотя, используя интерфейсы и определяя интерфейс только для чтения для класса и передавая его, можно гарантировать, что объекты могут передаваться по системе таким образом, чтобы их нельзя было изменить.
Платформа коллекций Java предоставляет способ создания неизменяемой оболочки Collection
с помощью Collections.unmodifiableCollection()
и подобные методы.
Метод в Java может быть объявлен «финальным», что означает, что его нельзя переопределить в подклассах.
С#
[ редактировать ]В C# квалификатор readonly
оказывает такое же влияние на элементы данных, что и final
делает на Java и const
делает на C++; модификатор const
имеет эффект, аналогичный (но типизированный и ограниченный классом) эффекту #define
в С++. Другой эффект Java, запрещающий наследование. final
при применении к методам и классам в C# вызывается с помощью ключевого слова sealed
.
В отличие от C++, C# не позволяет помечать методы и параметры как const
. Однако можно также передавать подклассы, доступные только для чтения, и .NET Framework предоставляет некоторую поддержку для преобразования изменяемых коллекций в неизменяемые, которые могут передаваться как оболочки только для чтения.
По парадигме
[ редактировать ]Обработка констант существенно различается в зависимости от парадигмы программирования . Константная корректность является проблемой в императивных языках, таких как C++, поскольку по умолчанию привязки имен обычно создают переменные , которые могут варьироваться, как следует из названия, и, следовательно, если кто-то хочет пометить привязку как константу, это требует некоторого дополнительного указания. [б] В других парадигмах языков программирования возникают связанные с этим проблемы, при этом обнаруживаются некоторые аналоги константной корректности.
В функциональном программировании данные обычно являются постоянными по умолчанию, а не переменными по умолчанию. Вместо присвоения значения переменной (область хранения с именем и потенциально переменным значением) создается привязка имени к значению, например, с помощью let
построить на многих диалектах Лиспа . В некоторых функциональных языках, особенно мультипарадигмальных, таких как Common Lisp , изменение данных является обычным явлением, тогда как в других его избегают или считают исключительным; это относится к Scheme (еще один диалект Лиспа), который использует set!
конструкция для изменения данных с помощью ! восклицательный знак, обращающий на это внимание. Такие языки по умолчанию достигают целей константной корректности, привлекая внимание к модификации, а не к постоянству.
В ряде объектно-ориентированных языков существует концепция неизменяемого объекта , которая особенно используется для базовых типов, таких как строки; известные примеры включают Java, JavaScript, Python и C#. Эти языки различаются тем, могут ли определенные пользователем типы быть помечены как неизменяемые, и могут ли они позволять помечать определенные поля (атрибуты) объекта или типа как неизменяемые.
В некоторых мультипарадигмальных языках, допускающих как объектно-ориентированный, так и функциональный стили, обе эти функции могут комбинироваться. Например, в объектах OCaml поля по умолчанию являются неизменяемыми и должны быть явно отмечены ключевым словом mutable
быть изменчивыми, тогда как в Scala привязки явно неизменяемы, если они определены с помощью val
для «значения» и явно изменяем, если определено с помощью var
для «переменной».
Соглашения об именах
[ редактировать ]Соглашения об именах констант различаются. Некоторые просто называют их так же, как и любую другую переменную. Другие используют заглавные буквы и подчеркивания для констант аналогично их традиционному использованию для символических макросов, например: SOME_CONSTANT
. [7] В венгерской записи «k» префикс обозначает константы, а также макросы и перечислимые типы .
Одно из установленных соглашений заключается в том, что в Ruby любая переменная, начинающаяся с заглавной буквы, считается константой, включая имена классов.
См. также
[ редактировать ]- Адресные константы для IBM/360 и Z/Architecture платформ
Примечания
[ редактировать ]- ^ В некоторых случаях это можно обойти, например, используя самомодифицирующийся код или перезаписав ячейку памяти , в которой хранится значение.
- ^ Это не универсально: например, в Ada входные параметры и параметры цикла неявно постоянны.
Ссылки
[ редактировать ]- ^ Пр. Информация о системах IBM . Набор инструкций — Справочник по языку ассемблера для PowerPC.
- ^ Буч, Грейди (1983). Разработка программного обеспечения с использованием Ada . Бенджамин Каммингс . стр. 116–117 . ISBN 0-8053-0600-5 .
- ^ Jump up to: а б с Шиллинг, Джонатан Л. (апрель 1995 г.). «Динамически значимые константы: недостаточно используемая функция языка» . Уведомления SIGPLAN . 30 (4): 13–20. дои : 10.1145/202176.202177 . S2CID 17489672 .
- ^ Перкинс, Дж. Практика программирования: анализ исходного кода Ada, разработанного для ВВС, армии и флота . Труды ТРИ-Ада '89. стр. 342–354. дои : 10.1145/74261.74287 .
- ^
Тимви (9 сентября 2010 г.). «Параметры функции C#, доступные только для чтения («константные»)» . Переполнение стека . Проверено 6 мая 2012 г.
[...] Затем вы можете объявить методы, тип параметра которых «сообщает», планирует ли он изменять переменную или нет:. [...] Это имитирует проверки во время компиляции, аналогичные проверке константности в C++. Как правильно заметил Эрик Липперт, это не то же самое, что неизменность. Но как программист C++, я думаю, вы это знаете.
- ^ «Технологическая сеть Oracle для разработчиков Java | Технологическая сеть Oracle | Oracle» . Java.sun.com. 14 августа 2013 г. Проверено 18 августа 2013 г.
- ^ Разработчик Microsoft Office XP: постоянные имена