#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;
, полностью свободному от ветвей.