Постоянные выражения C оценены во время компиляции или во времени выполнения?

31
задан Judge Maygarden 3 May 2016 в 15:17
поделиться

8 ответов

Макросы являются просто текстовой заменой, таким образом, в Вашем примере, пишущий TIMER_100_MS в программе необычный способ записать 32768 / 10.

Поэтому вопрос состоит в том, когда компилятор оценил бы 32768 / 10, который является постоянным интегральным выражением. Я не думаю, что стандарт требует какого-то конкретного поведения здесь (так как оценка и времени компиляции во время выполнения неразличима в действительности), но любой промежуточный достойный компилятор оценит его во время компиляции.

32
ответ дан 27 November 2019 в 21:32
поделиться

Я не знаю ни о каком стандарте, который гарантирует, что будет оптимизирован. Препроцессор заменит 32768/10 TIMER_100_MS, который Вы видите путем выполнения gcc-c. Чтобы видеть, оптимизирует ли компилятор далее, выполняет gcc-S и проверяют ассемблер. С gcc 4.1, даже без любых флагов оптимизации, это уменьшается до константы во время компиляции:

#include <stdlib.h>
#include <stdio.h>

#define EXTERNAL_CLOCK_FREQUENCY    32768
#define TIMER_1_S                   EXTERNAL_CLOCK_FREQUENCY
#define TIMER_100_MS                TIMER_1_S / 10

int main(int argc, char **argv)
{
  printf("%d\n", TIMER_100_MS);

  return(0);
}

gcc -S test.c
cat test.s

...
    popl    %ebx
    movl    $3276, 4(%esp)
    leal    LC0-"L00000000001$pb"(%ebx), %eax
    movl    %eax, (%esp)
    call    L_printf$stub
...
12
ответ дан 27 November 2019 в 21:32
поделиться

Большинство ответов в здесь сфокусированном на эффекте макроподстановки. Но я думаю, что он хотел знать, оценен ли

32768 / 10

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

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

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

Редактирование : я сожалею, что ответил на вопрос, как будто это было о C++. Замеченный сегодня Вы спросили о C. Переполнение в выражении считают как неопределенное поведение в C, независимо от того, происходит ли это в константном выражении или нет. Вторая точка также верна в C, конечно.

Редактирование : Как комментарий отмечает, если бы макросом заменяют в выражение как 3 * TIMER_100_MS, то это оценило бы (3 * 32768) / 10. Поэтому простой и прямой ответ "нет, Он не произошел бы во времени выполнения каждый раз, потому что подразделение не может произойти вообще из-за приоритета и правил ассоциативности" . Мой ответ выше предполагает, что макросом всегда заменяют таким образом, что подразделение на самом деле происходит.

26
ответ дан 27 November 2019 в 21:32
поделиться

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

Однако Вы не должны писать:

#define TIMER_100_MS      TIMERB_1_S / 10

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

#define TIMER_100_MS      (TIMERB_1_S / 10)

Рассмотрите:

i = 10 * TIMER_100_MS;

первый случай дал бы 32768 ((10 * TIMERB_1_S) / 10), вторые 32760 (10 * (TIMERB_1_S / 10)). Не критическое различие здесь, но НЕОБХОДИМО знать о нем!

11
ответ дан 27 November 2019 в 21:32
поделиться

Будет, операция 32768 / 10 происходит во времени выполнения каждый раз, когда я использую макрос TIMERB_100_MS?

Каждое место в Вашем коде, где Вы используете TIMERB_100_MS, это будет заменено 32768 / 10 препроцессором.

, Становится ли то выражение далее оптимизированным (оно оценивает к константе) до Вашего компилятора.

8
ответ дан 27 November 2019 в 21:32
поделиться

Люди, это преобразование называют "сворачиванием констант", и даже большинство студенческих компиляторов делает это. Пока Вам создал компилятор кто-то не Вы или Ваш сосед по комнате колледжа, и Вы компилируете статически типизированный язык, можно рассчитывать на него даже без включенной оптимизации. Это - другой разговор, если Вы имеете дело с некоторым дурацким динамическим языком, которому позволяют изменить значение /.

8
ответ дан 27 November 2019 в 21:32
поделиться

Во время компиляции. Это - стандарт языка (и всегда были), и независимый на компиляторе.

Редактирование

комментатор А попросил ссылку - заключающий в кавычки из "Языка программирования C" 2-й выпуск Приложение A12.3 (p. 229):

А управляют строкой формы

#define identifier token-sequence 

причины препроцессор для замены последующих экземпляров идентификатора с данной последовательностью маркеров; при продвижении и запаздывании пробелом вокруг последовательности roken является Конец discaded

редактирования

-4
ответ дан 27 November 2019 в 21:32
поделиться

От Проект Комитета WG14/N1124 — 6 мая 2005 ISO/IEC 9899:TC2:

6.6 Константных выражений

Синтаксис

константное выражение:
        условное выражение

Описание

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

Ограничения

Константные выражения не должны содержать присвоение, инкремент, декремент, вызов функции или операторы запятой, кроме тех случаев, когда они содержатся в подвыражении, которое не оценено 96)

Каждое константное выражение должно оценить к константе, которая находится в диапазоне epresentable значений для его типа.

8
ответ дан 27 November 2019 в 21:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: