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

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

В компьютерном программировании константа является значением , который не может быть изменен программой во время нормального выполнения, т. Е. Значение является постоянным. Когда константа связана с идентификатором, она называется «именованной», хотя термины «константа» и «именованная константа» часто используются взаимозаменяемо. Это контрастирует с переменной, которая представляет собой идентификатор со значением, которое может быть изменено во время нормального выполнения, то есть значение является переменным. Константы полезны как для программистов, так и для компиляторов: для программистов они представляют собой форму самодокументированного кода и позволяют рассуждать о правильности, тогда как для компиляторов они позволяют во время компиляции и во время выполнения проверки, которые подтверждают, что допущения постоянства не нарушаются, и позволяют или упрощают некоторые оптимизации компилятора.

Существуют различные конкретные реализации общего понятия константы с тонкими различия, которые часто упускаются из виду. Наиболее важными из них являются: константы времени компиляции (со статическими значениями), константы времени выполнения (с динамическими значениями), неизменяемые объекты и типы констант (const ).

Типичные примеры констант времени компиляции включают математические константы, значения из стандартов (здесь максимальная единица передачи ) или значения внутренней конфигурации (здесь символов в строке ), такие как эти примеры C:

const float PI = 3.1415927; // максимальная точность с плавающей запятой 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 (); //...}
Содержание
  • 1 Использование
  • 2 Сравнение с литералами и макросами
  • 3 Константы с динамическими значениями
  • 4 Постоянные параметры функции
  • 5 Объектно-ориентированные константы
    • 5.1 Java
    • 5.2 C #
  • 6 По парадигме
  • 7 Соглашения об именах
  • 8 См. Также
  • 9 Примечания
  • 10 Ссылки
Использование

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

Значение константы определяется один раз, и на него можно ссылаться много раз в программе. Использование константы вместо указания одного и того же значения несколько раз может упростить сопровождение кода (как в не повторяйтесь ) и может быть самодокументированным путем предоставления значимого имени для значения, например, PIвместо 3.1415926.

Сравнение с литералами и макросами

Есть несколько основных способов выразить значение данных, которое не изменяется во время выполнения программы, которые согласованы в большом количестве языков программирования. Один из самых простых способов - просто записать литерал число, символ или строку в программный код, что просто на C, C ++ и подобных языках.

В языке ассемблера буквальные числа и символы выполняются с использованием инструкций «немедленного режима», доступных на большинстве микропроцессоров. Название «немедленно» происходит от значений, доступных немедленно из потока инструкций , в отличие от их косвенной загрузки путем поиска адреса памяти. С другой стороны, значения длиннее, чем длина слова микропроцессора, такие как строки и массивы, обрабатываются косвенно, и ассемблеры обычно предоставляют псевдооперацию «данные» для встраивания таких таблиц данных в программу.

Другой способ - определить символический макрос . Многие языки программирования высокого уровня и многие ассемблеры предлагают средство макроса, в котором программист может определять, как правило, в начале исходного файла или в отдельном файле определения имена для различных значений. Затем препроцессор заменяет эти имена соответствующими значениями перед компиляцией, в результате чего получается нечто функционально идентичное использованию литералов, с преимуществами скорости немедленного режима. Поскольку может быть трудно поддерживать код, в котором все значения записаны буквально, если значение используется каким-либо повторяющимся или неочевидным образом, это часто делается как макрос.

Третий способ - объявить и определить переменную как «постоянную». Глобальная или статическая переменная может быть объявлена ​​(или символ, определенный в сборке) с квалификатором ключевого слова, например const, constantили final, что означает, что ее значение будет установлено во время компиляции и не должно быть изменено во время выполнения. Компиляторы обычно помещают статические константы в текстовый раздел объектного файла вместе с самим кодом, в отличие от раздела данных, в котором хранятся неконстантные инициализированные данные. Некоторые компиляторы могут создавать раздел, специально посвященный константам. К этой области можно применить защиту памяти, чтобы предотвратить перезапись таких констант ошибочными указателями.

Эти константы во многом отличаются от литералов. Компиляторы обычно помещают константу в одну ячейку памяти, обозначенную символом, а не распределяют по исполняемому файлу, как в макросе. Хотя это исключает преимущества скорости немедленного режима, есть преимущества в эффективности памяти, и отладчики могут работать с этими константами во время выполнения. Кроме того, хотя макросы могут быть переопределены случайно из-за конфликта файлов заголовков в C и C ++, конфликтующие константы обнаруживаются во время компиляции.

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

#define PI 3.1415926535 const float pi2 = 3.1415926535;

в Ada есть универсальные числовые типы, которые при желании можно использовать:

pi: constant: = 3.1415926535; pi2: постоянное число с плавающей запятой: = 3,1415926535;

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

Константы с динамическими значениями

Помимо статических констант, описанных выше, многие процедурные языки, такие как Ada и C ++, расширяют концепция постоянства по отношению к глобальным переменным, которые создаются во время инициализации, локальным переменным, которые автоматически создаются во время выполнения в стеке или в регистрах, для динамически выделяемой памяти, доступ к которой осуществляется указателем, и для списков параметров в заголовках функций.

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

float func (const float ANYTHING) {const float XYZ = someGlobalVariable * someOtherFunction (ANYTHING);...}

выражение, которым инициализируется константа, не является константой. Использование постоянства здесь не обязательно для законности программы или семантической корректности, но имеет три преимущества:

  1. Читателю ясно, что объект не будет больше изменяться после установки
  2. Попытки изменить значение объекта (более поздние программисты, которые не полностью понимают логику программы) будут отклонены компилятором
  3. Компилятор может выполнять оптимизацию кода, зная, что значение объекта не изменится после создания.

Константы с динамическими значениями возникли как функция языка с АЛГОЛОМ 68. Исследования кода Ada и C ++ показали, что константы с динамическими значениями используются нечасто, обычно для 1% или менее объектов, хотя их можно было бы использовать гораздо больше, поскольку около 40–50% локальных неклассовых объектов фактически инвариантны. однажды созданный. С другой стороны, такие «неизменяемые переменные» обычно используются по умолчанию в функциональных языках, поскольку они отдают предпочтение стилям программирования без побочных эффектов (например, рекурсии) или делают большинство объявлений неизменяемыми по умолчанию. Некоторые языки, называемые чисто функциональными, даже полностью запрещают побочные эффекты.

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

Параметры постоянной функции

В C / C ++ можно объявить параметр функции или метода как постоянный. Это гарантия того, что этот параметр не может быть изменен после первого назначения (случайно). Если параметр является предопределенным (встроенным) типом, он вызывается значением и не может быть изменен. Если это пользовательский тип, переменная является адресом указателя, который также не может быть изменен. Однако содержимое объекта можно изменять без ограничений. Объявление параметров как констант может быть способом показать, что это значение не должно изменяться, но программист должен иметь в виду, что проверки модификации объекта не могут выполняться компилятором.

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

В C # ключевое слово constсуществует, но не имеет такого же эффекта для параметров функции, как в C / C ++. Однако есть способ «побудить» компилятор выполнить проверку, хотя это немного сложно.

Чтобы получить тот же эффект, сначала определены два интерфейса.

открытый интерфейс IReadable {IValueInterface aValue {получить; }} открытый интерфейс IWritable: IReadable {IValueInterface aValue {set; }} открытый класс AnObject: IWritable {private ConcreteValue _aValue; общедоступный IValueInterface aValue {получить {return _aValue; } установить {_aValue = значение как ConcreteValue; }}}

Затем определенные методы выбирают правильный интерфейс с возможностями только для чтения или чтения / записи:

public void doSomething (IReadable aVariable) {// Невозможно изменить переменную! } public void doSomethingElse (IWritable aVariable) {// Может изменять переменную, поэтому будьте осторожны! }
Объектно-ориентированные константы

Константная структура данных или объект упоминается как «неизменяемый » на объектно-ориентированном языке. Неизменяемость объекта дает некоторые преимущества при разработке программ. Например, его можно «скопировать», просто скопировав его указатель или ссылку, избегая трудоемкой операции копирования и сохраняя память.

Объектно-ориентированные языки, такие как C ++, еще больше расширяют постоянство. Отдельные члены структуры или класса могут быть сделаны константами, даже если класс не является. И наоборот, ключевое слово mutableпозволяет изменять член класса, даже если объект был создан как const.

. Даже функции могут быть константными в C ++. Смысл здесь в том, что для объекта, созданного как const, может быть вызвана только функция const; константная функция не изменяет неизменяемые данные.

C # имеет квалификаторы constи только для чтения; его const предназначена только для констант времени компиляции, тогда как readonly может использоваться в конструкторах и других приложениях времени выполнения.

Java

Java имеет квалификатор final, который предотвращает изменение ссылки и гарантирует, что она никогда не будет указывать на другой объект. Это не предотвращает внесение изменений в сам упомянутый объект. finalв Java в основном эквивалентен указателю constв C ++. Он не предоставляет другие возможности const.

. В Java квалификатор finalуказывает, что затронутый элемент данных или переменная не может быть назначена, как показано ниже:

заключительный интервал я = 3; я = 4; // Ошибка! Невозможно изменить «конечный» объект

Он должен быть разрешен компиляторами, где инициализируется переменная с маркером final, и это должно быть выполнено только один раз, иначе класс не будет компилироваться. Ключевые слова Java finalи C ++ constимеют одинаковое значение при применении с примитивными переменными.

const int i = 3; // Объявление C ++ i = 4; // Ошибка!

Что касается указателей, то ссылка finalв Java означает нечто похожее на указатель constв C ++. В C ++ можно объявить «тип указателя const».

Foo * const bar = mem_location; // Тип константного указателя

Здесь barдолжен быть инициализирован во время объявления и не может быть изменен снова, но то, что он указывает, можно изменить. Т.е. * bar = значениедопустимо. Он просто не может указывать на другое место. Заключительные ссылки в Java работают так же, за исключением того, что они могут быть объявлены неинициализированными.

final Foo i; // объявление Java

Примечание: Java не поддерживает указатели. Это связано с тем, что указатели (с ограничениями) являются способом доступа по умолчанию к объектам в Java, и Java не использует звездочки для их обозначения. Например, iв последнем примере является указателем и может использоваться для доступа к экземпляру.

Можно также объявить указатель на данные «только для чтения» в C ++.

const Foo * bar;

Здесь полосаможет быть изменена так, чтобы указывать на что угодно и когда угодно; только указанное значение не может быть изменено с помощью указателя bar. В Java нет эквивалентного механизма. Таким образом, также нет методов const. В Java нельзя обеспечить постоянную корректность, хотя, используя интерфейсы и определяя интерфейс только для чтения для класса и передавая его, можно гарантировать, что объекты могут передаваться по системе таким образом, что они не могут быть изменены. Среда коллекций Java предоставляет способ создания неизменяемой оболочки для Collectionс помощью Collections.unmodifiableCollection ()и аналогичных методов.

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

C #

В C # квалификатор readonlyоказывает такое же влияние на элементы данных, как finalв Java и constделает в C ++; модификатор constв C # имеет эффект, аналогичный (но типизированному и ограниченному по классу) эффекту #defineв C ++. (Другой эффект запрета наследования finalJava при применении к методам и классам вызывается в C # с помощью третьего ключевого слова, sealed.)

В отличие от C ++, C # не позволяет помечать методы и параметры как const. Однако можно также передавать подклассы, доступные только для чтения, и .NET Framework предоставляет некоторую поддержку для преобразования изменяемых коллекций в неизменяемые, которые могут передаваться как оболочки только для чтения.

По парадигме

Обработка констант значительно зависит от парадигмы программирования. Корректность констант - это проблема в императивных языках, таких как C ++, потому что по умолчанию привязки имен обычно создают переменные, которые могут варьироваться, как следует из названия, и, следовательно, если кто-то хочет пометить привязку как постоянный, это требует дополнительных указаний. В других парадигмах языков программирования возникают проблемы, связанные с обнаружением некоторых аналогов константной корректности.

В функциональном программировании данные обычно по умолчанию постоянные, а не переменные по умолчанию. Вместо присвоения значения переменной (пространство хранения с именем и потенциально значением переменной) создается привязка имени к значению, например, с помощью конструкции letво многих диалектах Лисп. В некоторых функциональных языках, особенно в многопарадигмальных, таких как Common Lisp, изменение данных является обычным делом, в то время как в других его избегают или считают исключительным; это случай Scheme (другой диалект Лиспа), который использует конструкцию set!для изменения данных, на что обращает внимание восклицательный знак !. Такие языки по умолчанию достигают целей константной корректности, обращая внимание на модификацию, а не на постоянство.

В ряде объектно-ориентированных языков (OOL) существует концепция неизменяемого объекта, который особенно используется для базовых типов, таких как строки; примечательные примеры включают Java, JavaScript, Python и C #. Эти языки различаются в зависимости от того, могут ли определяемые пользователем типы быть помечены как неизменяемые, и могут позволять помечать определенные поля (атрибуты) объекта или типа как неизменяемые.

В некоторых многопарадигмальных языках, допускающих как объектно-ориентированные, так и функциональные стили, обе эти функции могут быть объединены. Например, в OCaml поля объекта неизменяемы по умолчанию и должны быть явно помечены ключевым словом mutableкак изменяемые, тогда как в Scala привязки явно неизменяемы, определены с помощью valдля «значения» или явно изменяемый, определенный с помощью varдля «переменной».

Соглашения об именах

Соглашения об именах для констант различаются. Некоторые просто называют их, как любую другую переменную. Другие используют заглавные буквы и подчеркивания для констант аналогично их традиционному использованию для символьных макросов, например SOME_CONSTANT. В венгерской нотации префикс «k» обозначает константы, а также макросы и перечислимые типы.

Одно обязательное соглашение заключается в том, что в Ruby, любая переменная, начинающаяся с заглавной буквы, считается константой, включая имена классов.

См. Также
Примечания
Ссылки
Последняя правка сделана 2021-05-15 10:19:14
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте