Вопрос

Вот функция, которую я пишу на 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];
}

Теперь мои вопросы:

  1. Переменная «A» хранится в реестре, чтобы он не будет доступен снова и снова от RAM или Chache?
  2. Работа на 64-битной архитектуре, если я предположить, что «ARR» массив будет храниться в регистре, поскольку параметры функций хранятся в реестре в 64-битной арке?
  3. Насколько эффективна ли указатель типа литья? Я думаю, что это должно быть неэффективно вообще?

Любая помощь будет оценена.

С уважением

Это было полезно?

Решение

  1. a не может быть сохранено в реестре, поскольку вы приняли свой адрес. (Valdo правильно указывает, что действительно умный компилятор мог Оптимизировать массив доступ к битовым операциям и оставить a В реестре, но я никогда не видел компилятора сделать это, и я не уверен, что это будет быстрее быть быстрее).
  2. arr (сам указатель) хранится в реестре (%edi, на AMD64). То Содержание массива в памяти.
  3. Литье типа указателя сами по себе часто не генерирует код вообще. Однако делать глупые вещи с литяками типа могут привести к очень неэффективному коду или даже к коду, чье поведение не определено.

Похоже, вы пытаетесь развернуть байты в массиве, а затем засунуть их в число, а машинный код генерирует ваш пример, не является ужасно плохо для этого. Предложение Дэвида использовать операции Shift и Mask вместо этого - это хорошо (это также избегает проблем, если ваш код когда-либо должен работать на большую эндинную машину), и есть также инструкции SSE Vector Persone, но я слышал, что они видны боли использовать.

Кстати, вы должны сделать возвратный тип вашего примера функции unsigned long и положи return a; в самом конце; Тогда вы можете использовать gcc -O2 -S и увидеть именно то, что вы получаете от компиляции. Без изменения до возвращения a, GCC будет весело оптимизировать все тело функции, поскольку у него нет видимых побочных эффектов.

Другие советы

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

Операции Array собираются сделать его сложнее для компилятора использовать регистры для этого, потому что обычно не являются инструкцией, которые делают такие вещи, как «Загрузка 8 битов из 3-го байта регистра A». (Оптимизирующий компилятор мог Выясните, что можно сделать это с сдвигами / масками, но я не уверен, насколько это может).

  1. Вопрос о если переменная a Будут храниться в реестре - вопрос оптимизации. Так как нет volatile Модификатор IMHO Умный компилятор сделает это.

  2. Это вопрос о вызове. Если по Конвенции один параметр указателя передается в реестре - так будет arr.

  3. Литье типа указателя не является операцией, которая интерпретирует 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 (который быстро становится бесполезной с оптимизацией).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top