Из Википедии, бесплатной энциклопедии
  (Перенаправлено с Constant (информатика) )
Перейти к навигации Перейти к поиску

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

Существуют различные конкретные реализации общего понятия константы с тонкими различиями, которые часто упускаются из виду. Наиболее важными из них являются: константы времени компиляции (со статическими значениями), константы времени выполнения (с динамическими значениями), неизменяемые объекты и типы констант ( 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 . длина ();  // ... }

Используйте [ редактировать ]

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

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

Сравнение с литералами и макросами [ править ]

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

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

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

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

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

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

#define PI 3.1415926535const  float  pi2  =  3,1415926535 ;

а в Аде при желании можно использовать универсальные числовые типы:

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

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

Константы с динамическими значениями [ править ]

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

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

float  func ( const  float  НИЧЕГО )  {  const  float  XYZ  =  someGlobalVariable * someOtherFunction ( НИЧЕГО );  ... }

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

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

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

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

Постоянные параметры функции [ править ]

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

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

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

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

открытый  интерфейс  IReadable {  IValueInterface  aValue  {  получить ;  } }открытый  интерфейс  IWritable  :  IReadable {  IValueInterface  aValue  {  set ;  } }общественный  класс  AnObject  :  IWritable {  частное  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и readonlyквалификатор; его константа предназначена только для констант времени компиляции, в то время как только чтение может использоваться в конструкторах и других приложениях времени выполнения.

Java [ править ]

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

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

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

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

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

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

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

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

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

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

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

const  Foo  * bar ;

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

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

C # [ править ]

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

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

По парадигме [ править ]

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

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

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

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

Соглашения об именах [ править ]

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

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

См. Также [ править ]

  • Адрес константы для IBM / 360 и Z / Архитектура платформы

Заметки [ править ]

  1. ^ В некоторых случаях ожидание постоянства можно обойти, например, используя самомодифицирующийся код или перезаписав место в памяти, где хранится значение.
  2. ^ Это не универсально: например, в Ada входные параметры и параметры цикла неявно постоянны.

Ссылки [ править ]

  1. ^ Ex. Системная информация IBM . Набор инструкций - Справочник по языку ассемблера для PowerPC.
  2. ^ Буча, Грейди (1983). Разработка программного обеспечения с Ada . Бенджамин Каммингс . С.  116–117 . ISBN 0-8053-0600-5. CS1 maint: обескураженный параметр ( ссылка )
  3. ^ a b c Шиллинг, Джонатан Л. (апрель 1995 г.). «Константы с динамическим значением: малоиспользуемая языковая функция». Уведомления SIGPLAN . 30 (4): 13–20. DOI : 10.1145 / 202176.202177 .
  4. ^ Перкинс, Дж. А. Практики программирования: анализ исходного кода на языке Ada, разработанный для ВВС, армии и флота . Материалы ТРИ-Ада '89. С. 342–354. DOI : 10.1145 / 74261.74287 .
  5. ^ Timwi (2010-09-09). «Параметры функции C #, доступные только для чтения (как« const »)» . https://stackoverflow.com/ : Переполнение стека . Проверено 6 мая 2012 . [...] Затем вы можете объявить методы, тип параметра которых «сообщает», планирует ли он изменять переменную или нет :. [...] Это имитирует проверки во время компиляции, аналогичные проверкам константности в C ++. Как правильно заметил Эрик Липперт, это не то же самое, что неизменность. Но, как программист на C ++, я думаю, вы это знаете. CS1 maint: обескураженный параметр ( ссылка )
  6. ^ "Технологическая сеть Oracle для разработчиков Java | Технологическая сеть Oracle | Oracle" . Java.sun.com. 2013-08-14 . Проверено 18 августа 2013 . CS1 maint: обескураженный параметр ( ссылка )
  7. ^ Разработчик Microsoft Office XP: постоянные имена