stringtranslate.com

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

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

Константы полезны как для программистов, так и для компиляторов : для программистов они представляют собой форму самодокументируемого кода и позволяют рассуждать о корректности , тогда как для компиляторов они позволяют выполнять проверки во время компиляции и во время выполнения , которые проверяют, что предположения о постоянстве не нарушаются. [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 ;    

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

Пи  :  константа  :=  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] С другой стороны, такие «неизменяемые переменные», как правило, используются по умолчанию в функциональных языках , поскольку они отдают предпочтение стилям программирования без побочных эффектов (например, рекурсии) или делают большинство объявлений неизменяемыми по умолчанию, например 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указывает, что затронутый элемент данных или переменная не может быть назначен, как показано ниже:

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

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

константный интервал я = 3 ; // Объявление C++ i = 4 ; // Ошибка!        

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

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

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

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

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

В C++ также можно объявить указатель на данные, доступные только для чтения.

константа Foo * бар ;  

Здесь barможно изменить, чтобы указать что угодно и когда угодно; просто это указанное значение не может быть изменено с помощью bar указателя.

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

Платформа коллекций Java предоставляет способ создания неизменяемой оболочки переходного Collectionотверстия и подобных методов.Collections.unmodifiableCollection()

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

С#

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

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

По парадигме

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

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

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

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

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

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

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

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

Примечания

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

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

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