Преимущества констант - PullRequest
14 голосов
/ 26 марта 2010

Я понимаю, что одно из больших преимуществ констант заключается в том, что вам не нужно проходить и обновлять код, где эта константа используется повсеместно. Это здорово, но допустим, вы явно не объявляете это как константу. Какие преимущества существуют для того, чтобы взять переменную, которая на самом деле не изменяется, и сделать ее константой, это сэкономит на обработке и / или размере кода ... и т. Д.

По сути, у меня есть программа, которую компилятор говорит, что конкретная переменная не изменилась и, таким образом, может быть объявлена ​​константой, я просто хотел знать, какая польза от добавления к ней квалификатора константы, если она Разница в том, что внесение этого изменения не добавляет ценности, и, следовательно, нет смысла тратить время (этот сценарий происходит более чем в одном месте), возвращаясь и «исправляя» все эти переменные.

Ответы [ 14 ]

22 голосов
/ 26 марта 2010

Если вы объявляете переменную константой, оптимизатор часто может исключить ее с помощью «постоянного сворачивания», что ускоряет вашу программу и экономит ваше пространство. В качестве примера рассмотрим это:

var int a = 5;
const int b = 7;
...
c = process(a*b);

В итоге компилятор создаст инструкцию для умножения a на 7 и передаст ее в «process», сохраняя результаты в c. Однако в этом случае:

const int a = 5;
const int b = 7;
...
c = process(a*b);

Компилятор просто передает 35 для обработки и даже не кодирует умножение. Кроме того, если компилятор знает, что процесс не имеет побочных эффектов (т. Е. Является простым вычислением), то он даже не вызовет процесс. Он просто установит c в качестве возвращаемого значения процесса (35), сохранив вам вызов функции.

21 голосов
/ 26 марта 2010

Если вы объявите что-то как константу, а затем случайно попытаетесь изменить его значение в своем коде, компилятор сообщит вам о вашей ошибке. Эта форма статической проверки типов на самом деле является основной причиной использования констант.

6 голосов
/ 26 марта 2010

Многое зависит от того, насколько хорош ваш оптимизатор.

Хороший оптимизатор заменит константные ссылки на литеральные значения во время компиляции. Это экономит циклы процессора, поскольку сгенерированный машинный код работает с непосредственными значениями вместо того, чтобы загружать значение из памяти.

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

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

4 голосов
/ 26 марта 2010

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

3 голосов
/ 26 марта 2010

Возможно, что компилятор уменьшит размер кода .. например, в пакете System вы найдете (на компьютере с архитектурой x86)

type Bit_Order is (High_Order_First, Low_Order_First);
Default_Bit_Order : constant Bit_Order := Low_Order_First;

так что дано

case System.Default_Bit_Order is
   when System.High_Order_First =>
      --  Big-endian processing
   when System.Low_Order_First =>
      --  Little-endian processing
end case;

компилятор может полностью устранить «неправильную» ветвь, пока ваш код сохраняет свою переносимость. С GNAT вам нужно использовать оптимизацию не по умолчанию, чтобы это произошло: -O2 Я думаю.

Обе ветви должны быть компилируемыми - это оптимизация, а не #ifdef обработка.

3 голосов
/ 26 марта 2010

Как вы указали, вы не можете получить прямую выгоду от изменения неизменяемых переменных в явные константы. Тем не менее, при анализе программы одна проверка, которая делается, заключается в том, чтобы посмотреть на точку объявления переменной в точку ссылки на переменную. Таким образом, такие метрики, как переменные, к которым обращаются до объявления, или устанавливаемые и сбрасываемые до ссылки и т. Д., Могут указывать на ошибки.

Путем явного объявления констант в качестве констант компилятор и инструменты анализа знают, что вы не собираетесь сбрасывать переменную в любое время.

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

2 голосов
/ 30 марта 2010

Есть еще одно преимущество: размер стека и сегмента данных.

Рассмотрим:

function Recurser(i : Integer) return Integer is
  ia : array(0..9) of Integer
          := (1, 2, 3, 4, 5, 6, 7, 8, 9, 1000);
  r : Integer;
begin
   if i = 0 then return 0; end if;
   r := ia(i mod 10);
   return r + Recurser(i - 1);
end;

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

Переменные уровня пакета также увеличивают размер сегмента данных. Увеличение ваших требований к памяти.

2 голосов
/ 27 марта 2010

Это на самом деле не специфичный для Ады вопрос.

Общие преимущества постоянных над переменными:

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

Ada конкретные преимущества:

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

Пример:

Seconds_Per_Minute : constant := 60;
Secs_Per_Min       : Integer  := 60;

type Seconds_Offset is 0 .. Integer'last; --'

Min1, Secs1 : Integer;
Min2, Secs2 : Seconds_Offset;

...
--// Using the named number, both of these compile no problem.
Secs1 := Min1 * Seconds_Per_Minute;
Secs2 :=  Min2 * Seconds_Per_Minute;

--// The second line here gives an error, since Integer is a 
--// different type than Seconds_Offset.
Secs1 := Min1 * Secs_Per_Min;
Secs2 := Min2 * Secs_Per_Min;
2 голосов
/ 26 марта 2010

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

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

Во-вторых, как заявили itsmatt и jball, он позволяет логически рассматривать элемент как элемент постоянной конфигурации, а не как «переменную»; особенно в языках программирования более высокого уровня и в интерпретируемых языках.

2 голосов
/ 26 марта 2010

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

int b=x*f;
int c=y*f;

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

...