Компилятор C / выполняет операции сдвига во время компиляции? - PullRequest
2 голосов
/ 14 мая 2011

Было упомянуто, что хорошо написанный компилятор для C должен выполнять операторы сдвига во время компиляции (то есть не во время выполнения); например в этом коде сдвиг влево - <<. Кто-нибудь может подтвердить обоснованность этого? </p>

Код:

constant unsigned int elements = length/8 + (length % y > 0 ? 1 : 0);  
unsigned char bit_arr[elements];

Псевдо-код:

bit_arr[i] |= (1 << j); // Set 
bit_arr[i] &= ~(1 << j);  // Unset
if( bit_arr[i] & (1 << j) ) // Test

Ответы [ 7 ]

4 голосов
/ 14 мая 2011

Что ты на самом деле спрашиваешь? Вы имеете в виду "компилятор сам сделает сдвиг"? Если это то, что вы спрашиваете, ответ "это зависит" :). Если смещаемое число и размер сдвига являются константами времени компиляции, компилятор почти наверняка выполнит сдвиг (хотя это и не обязательно). В противном случае он сгенерирует код нижнего уровня, который будет выполнять сдвиг (который часто будет отдельной машинной инструкцией).

3 голосов
/ 14 мая 2011

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

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

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

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

3 голосов
/ 14 мая 2011

Любой компилятор, соответствующий стандарту C, будет предоставлять операторы сдвига << и >>, как указано в стандарте в §6.5.7. Они будут работать без проблем с целочисленными выражениями (будь они постоянными или нет) 1 ).

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

<ч /> 1. Как указано в §6.5.7 ¶2, единственным ограничением на операнды является

Каждый из операндов должен иметь целочисленный тип.

<ч />

Все это больше не актуально, так как вопрос полностью изменился.

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

1 голос
/ 14 мая 2011

Одним из примеров осуществляемых компилятором сдвигов является следующий пример (с неопределенным поведением):

#include <stdio.h>

int main(void) {
    const int i = 32;
    printf("%d %d\n", 1 << 32, 1 << i);
    return 0;
}

С gcc 4.3.4 на Cygwin gcc foo.c; ./a дает 0 1 вместо ожидаемого 0 0.( gcc выдает предупреждение компилятора, а с -O3 вы получите ожидаемый результат с двумя предупреждениями.) По этой причине см. SO GCC left shiftпереполнение .

0 голосов
/ 14 мая 2011

Есть ли зависимость j от константы против переменной?

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

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

0 голосов
/ 14 мая 2011

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

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

0 голосов
/ 14 мая 2011

Каждый компилятор C должен реализовывать операторы сдвига, так как они являются частью языка.Нет никаких ограничений на j.

РЕДАКТИРОВАТЬ: Так как вы полностью изменили вопрос: Да, для оптимизации, конечно, j должен быть постоянной времени компиляции, в противном случае,как компилятор должен знать его значение во время компиляции, но оптимизация арифметических инструкций с постоянными операндами - это одна из первых вещей, которые необходимо выполнить при оптимизации кода.На самом деле, я думаю, что VC и gcc делают это, даже когда уровень оптимизации не активирован. Это просто очевидно.

...