Оценка макроса во время компиляции?

#c

#c

Вопрос:

 #define CONVERT(val, qin, qout) ((qin > qout) ? (val >> (qin-qout) ) : (val << (qout-qin)))

void f(void)
{
    ...
    y = CONVERT(x, 25, 31);
}
  

Будет ли приведенный выше макрос оцениваться GCC во время компиляции? Я имею в виду (qin > qout) часть. Я пытаюсь получить только y = x << (31-25) после завершения компиляции.

Комментарии:

1. Компилятор должен иметь возможность выполнять свертку с постоянными значениями, если это то, что вас интересует. На самом деле вы, вероятно, имели бы y = x << (6) . Вы выполнили сборку с включенной оптимизацией и проверили сгенерированный код?

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

3. Обратите внимание, что ответ на этот вопрос не имеет ничего общего с оценкой макроса. Вы можете увидеть, что препроцессор делает с макросом, скомпилировав с -E . Это оптимизатор, который будет предварительно вычислять результаты тернарного оператора.

4. проблема может заключаться в том, что в расширении макроса есть литерал (1 >> (25 -31)) . Это может вызвать предупреждения о неопределенном поведении (но код все равно будет вести себя корректно).

5. Кроме того, вам действительно следует заключить параметры в круглые скобки в расширении макроса, чтобы избежать проблем, когда аргументы являются чем-то иным, чем основным выражением. С вашим текущим определением макроса y = CONVERT(x, 25, 31); и y = CONVERT(x, 30 - 5, 31); было бы установлено y другое значение, что, вероятно, не то, что вы хотите.

Ответ №1:

В этом случае qin > qout часть будет выглядеть как целочисленное постоянное выражение, в которое компилятор может оптимизировать 1 или 0 теоретически.

На практике он даже этого не делает. Глядя на то, как реальные компиляторы на самом деле обрабатывают ваш пример, gcc и clang at -O0 (оптимизация отключена) генерируют только код для сдвига влево, опуская условную проверку и ветвление ?: , а также второй операнд, который никогда не является истинным.

Машинный код в конечном итоге сводится к эквиваленту y = x << 6; , полностью свободному от ветвей.