Постоянный (компьютерное программирование) - Constant (computer programming)

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

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

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

const плавать ЧИСЛО ПИ = 3.1415927;  // максимальная точность одиночного числа с плавающей запятойconst беззнаковый int MTU = 1500;  // Ethernet v2, RFC 894const беззнаковый int КОЛОННЫ = 80;

Типичными примерами постоянных времени выполнения являются значения, вычисленные на основе входных данных функции, например этот пример C ++:

пустота ж(стандартное::нить s) {  const size_t л = s.длина();  // ...}

Использовать

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

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

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

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

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

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

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

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

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

#define PI 3.1415926535const плавать pi2 = 3.1415926535;

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

число Пи : постоянный := 3.1415926535;pi2 : постоянный плавать := 3.1415926535;

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

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

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

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

плавать func(const плавать ЧТО-ЛИБО) {    const плавать XYZ = someGlobalVariable*someOtherFunction(ЧТО-ЛИБО);    ...}

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

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

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

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

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

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

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

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

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

общественный интерфейс IReadable{    IValueInterface ценность { получать; }}общественный интерфейс IWritable : IReadable{    IValueInterface ценность { набор; }}общественный учебный класс Объект : IWritable{    частный ConcreteValue _ценность;    общественный IValueInterface ценность    {        получать { возвращаться _ценность; }        набор { _ценность = ценить в качестве ConcreteValue; }    }}

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

общественный пустота сделай что-нибудь(IReadable Переменная){    // Невозможно изменить переменную!}общественный пустота doSomethingElse(IWritable Переменная){    // Может изменять переменную, поэтому будьте осторожны!}

Объектно-ориентированные константы

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

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

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

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

Ява

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

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

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

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

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

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

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

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

окончательный Фу я; // объявление Java

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

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

const Фу *бар;

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

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

C #

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

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

По парадигме

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

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

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

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

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

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

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

Смотрите также

Примечания

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

Рекомендации

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