Символические константы в C - PullRequest
       0

Символические константы в C

2 голосов
/ 02 сентября 2011

Рассмотрение символических констант с использованием макросов, констант перечисления и объектов const. В макросах область действия является глобальной и не может быть ограничена локальной областью действия, что является серьезным недостатком. Константы перечисления не могут использоваться в ситуациях, отличных от целых чисел. Константы перечисления не могут быть представлены в формате с плавающей запятой или длинной. Const объекты могут иметь локальную область видимости, могут быть представлены в различных типах данных. Но в c декларирование «int const a» или «const int a» делает значение константным, а int-буфер [a] не разрешен в c. Но в c ++ int-буфер [a] разрешен, поскольку он принимает «const a». "только константа компилятора.

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

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

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

Ответы [ 3 ]

5 голосов
/ 02 сентября 2011

Объект, объявленный с const, не является константой (точнее, его имя не является константным выражением).Ключевое слово const не означает «постоянный», оно означает «только для чтения».Поэтому, учитывая:

const int answer = 42;
printf("The answer is %d\n", answer);

, в принципе, для оценки вызова printf необходимо извлечь значение answer из хранилища, прежде чем передать его в функцию printf.

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

printf("The answer is %d\n", 42);

(gcc делаетэто с -O1 или лучше. Если вы не укажете -O..., тогда код фактически извлекает значение объекта - но тогда, если вы не запрашиваете оптимизацию, вы говорите компилятору, что неочень заботится о производительности.)

(Действительно умный компилятор может сгенерировать код, эквивалентный

puts("The answer is 42");

.)

Реальное отличие состоит в том, что имя answer не можетиспользоваться в контекстах, которые требуют постоянного выражения.Например, case answer: ... было бы допустимо в C ++, но недопустимо в C.

Обратите внимание, что int arr[answer]; действительно допустимо, по крайней мере, в C99, что позволяет использовать массивы переменной длины.Это было бы в равной степени законно, если бы вы написали

const int answer = rand() % 100 + 1;

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

Asдля трюка enum:

enum { answer = 42; }

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

Так что может будет штрафом за производительность для const int answer = 42;, а не #define answer 42, но на практике это простоограничить контексты, в которых вы можете его использовать.

4 голосов
/ 02 сентября 2011

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

  1. static const int CONSTANT = 10;

    Недостатки: его нельзя использовать в «константе»выражение ", поэтому вы не сможете использовать его для размеров массивов для массивов со статической продолжительностью хранения или для случаев в выражениях switch.

  2. enum { CONSTANT = 10 };

    Недостатки: Он не может иметь тип, отличный от int.Например, 1U << 31 не является строго переносимым к системам с 32-битным int, и 1ULL << 48, вероятно, сломается во многих системах.Не имеет адреса.

  3. #define CONSTANT 10

    Недостатки: он плохо взаимодействует с отладчиком и мешает нормальным правилам области видимости Си.Не имеет адреса.

В современном компиляторе все три из этих должны иметь одинаковые свойства производительности во время выполнения.Так что не беспокойтесь о производительности.

Примечание: Это не относится к следующему:

const int CONSTANT = 10;

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

1 голос
/ 02 сентября 2011

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

const int a = 7;

на самом деле представляет собой int, который хранится где-то и долженбыть прочитанным оттуда.Например, в машинном коде x86 он читается как:

MOV  EAX,[a]

, и это реальный доступ к памяти.OTOH, перечисление типа

enum X { a=7, b, c };

читается как непосредственное значение

MOV  EAX,7

, которое обычно быстрее, также в других процессорах.

Я думаю, чтоэто то, что подразумевалось в строке, которую вы указали.

Конечно, хороший компилятор может на самом деле сделать вывод, что значение const int a = 7; никогда не изменяется, поэтому он может принять значение машинного кода emit, который на самом делеMOV EAX,7, но на это нет никаких гарантий.Перечисления являются непосредственными значениями, поэтому они будут гарантированно использоваться таким образом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...