Вопрос
Вот функция, которую я пишу на 64-битной машине Linux.
void myfunc(unsigned char* arr) //array of 8 bytes is passed by reference
{
unsigned long a = 0; //8 bytes
unsigned char* LL = (unsigned char*) &a;
LL[0] = arr[6];
LL[1] = arr[3];
LL[2] = arr[1];
LL[3] = arr[7];
LL[4] = arr[5];
LL[5] = arr[4];
LL[6] = arr[0];
LL[7] = arr[2];
}
Теперь мои вопросы:
- Переменная «A» хранится в реестре, чтобы он не будет доступен снова и снова от RAM или Chache?
- Работа на 64-битной архитектуре, если я предположить, что «ARR» массив будет храниться в регистре, поскольку параметры функций хранятся в реестре в 64-битной арке?
- Насколько эффективна ли указатель типа литья? Я думаю, что это должно быть неэффективно вообще?
Любая помощь будет оценена.
С уважением
Решение
a
не может быть сохранено в реестре, поскольку вы приняли свой адрес. (Valdo правильно указывает, что действительно умный компилятор мог Оптимизировать массив доступ к битовым операциям и оставитьa
В реестре, но я никогда не видел компилятора сделать это, и я не уверен, что это будет быстрее быть быстрее).arr
(сам указатель) хранится в реестре (%edi
, на AMD64). То Содержание массива в памяти.- Литье типа указателя сами по себе часто не генерирует код вообще. Однако делать глупые вещи с литяками типа могут привести к очень неэффективному коду или даже к коду, чье поведение не определено.
Похоже, вы пытаетесь развернуть байты в массиве, а затем засунуть их в число, а машинный код генерирует ваш пример, не является ужасно плохо для этого. Предложение Дэвида использовать операции Shift и Mask вместо этого - это хорошо (это также избегает проблем, если ваш код когда-либо должен работать на большую эндинную машину), и есть также инструкции SSE Vector Persone, но я слышал, что они видны боли использовать.
Кстати, вы должны сделать возвратный тип вашего примера функции unsigned long
и положи return a;
в самом конце; Тогда вы можете использовать gcc -O2 -S
и увидеть именно то, что вы получаете от компиляции. Без изменения до возвращения a
, GCC будет весело оптимизировать все тело функции, поскольку у него нет видимых побочных эффектов.
Другие советы
Возможно, вы лучше всего использовать явные инструкции Shift и Mask, чтобы выполнить это, а не использовать индексирование массива.
Операции Array собираются сделать его сложнее для компилятора использовать регистры для этого, потому что обычно не являются инструкцией, которые делают такие вещи, как «Загрузка 8 битов из 3-го байта регистра A». (Оптимизирующий компилятор мог Выясните, что можно сделать это с сдвигами / масками, но я не уверен, насколько это может).
Вопрос о если переменная
a
Будут храниться в реестре - вопрос оптимизации. Так как нетvolatile
Модификатор IMHO Умный компилятор сделает это.Это вопрос о вызове. Если по Конвенции один параметр указателя передается в реестре - так будет
arr
.Литье типа указателя не является операцией, которая интерпретирует CPU. Для него не генерируется код. Это только информация для компилятора о том, что вы имеете в виду.
(На самом деле иногда отливка делает дополнительный код, но это связано с несколькими наследованием и полиморфизмом)
Зависит от вашего уровня оптимизации. Вы можете изучить сборку, чтобы ответить на ваши вопросы. С GCC используйте флаг «-С».
gcc -S -O0 -o /tmp/xx-O0.s /tmp/xx.c
gcc -S -O3 -o /tmp/xx-O3.s /tmp/xx.c
Сгенерированная сборка полностью разные. (Обязательно сделайте return a;
Изменения предложены Zack..)
Смотрите также это сообщение Для намеков на то, как генерировать смешанный список C / Assember (который быстро становится бесполезной с оптимизацией).