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 . length (); // ... }         

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

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

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

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

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

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

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

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

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

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

#определить ПИ 3.1415926535константа float pi2 = 3.1415926535 ;    

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

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

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

Динамически-значимые константы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Ява

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

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

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

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

const int i = 3 ; // Декларация C++ i = 4 ; // Ошибка!        

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

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

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

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

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

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

константа Foo * bar ;  

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

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

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

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

С#

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

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

По парадигме

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

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

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

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

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

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

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

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

Примечания

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

Ссылки

  1. ^ Пример. IBM Systems Information. Набор инструкций — Справочник по языку ассемблера для PowerPC.
  2. ^ Booch, Grady (1983). Разработка программного обеспечения с Ada . Benjamin Cummings . стр. 116–117. ISBN 0-8053-0600-5.
  3. ^ abc Schilling, Jonathan L. (апрель 1995 г.). «Динамически-значимые константы: недостаточно используемая языковая возможность». SIGPLAN Notices . 30 (4): 13–20. doi : 10.1145/202176.202177 . S2CID  17489672.
  4. ^ Перкинс, JA Практики программирования: Анализ исходного кода Ada, разработанного для ВВС, армии и флота . Труды TRI-Ada '89. С. 342–354. doi :10.1145/74261.74287.
  5. ^ Timwi (2010-09-09). "Параметры функций C# только для чтения ("const"-like)". Stack Overflow . Получено 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 Developer: Константные имена