Какой из этих двух методов преобразования этого массива в целое число вы бы предложили? - PullRequest
1 голос
/ 06 ноября 2010

рассмотрим следующий массив байтов, который предназначен для преобразования в одно целое число без знака:

unsigned char arr[3] = {0x23, 0x45, 0x67};

каждый байт представляет собой эквивалентный байт в целом числе, теперь какой из следующих методов вы бы предложили специальнопо производительности:

unsigned int val1 = arr[2] << 16 | arr[1] << 8 | arr[0];
//or
unsigned int val2=arr[0];
*((char *)&val2+1)=arr[1];
*((char *)&val2+2)=arr[2];

Ответы [ 6 ]

6 голосов
/ 06 ноября 2010

Я предпочитаю первый метод, потому что он портативный. Второе не связано с проблемами endianness .

4 голосов
/ 06 ноября 2010

Это зависит от вашего конкретного процессора, много .

Например, в PowerPC вторая форма - запись через указатели символов - сталкивается с хитрой деталью реализации, называемой load-hit-store . Это сбой ЦП, который происходит, когда вы сохраняете данные в памяти, а затем снова читаете их, прежде чем хранилище будет завершено. Операция загрузки не может быть завершена до тех пор, пока хранилище не будет завершено (большинство PPC не имеют пересылки хранилища памяти), и хранилище может потребоваться много циклов, чтобы перейти из ЦП в кэш памяти.

Из-за того, как хранилище и арифметические единицы расположены в конвейере, ЦПУ придется полностью очистить конвейер до тех пор, пока хранилище не завершится: это может быть остановка из двадцати циклов или более, в течение которых ЦП остановился. В общем, запись в память и последующее чтение сразу очень плохо на этой платформе. Таким образом, в этом случае последовательные битовые сдвиги будут намного быстрее, так как все они происходят в регистрах, и не повлекут за собой остановку конвейера.

В серии Pentium ситуация может полностью измениться, потому что этот набор микросхем имеет переадресацию хранилища и архитектуру быстрого стека и относительно немного архитектурных регистров. На Core Duos и i7s он может снова повернуть вспять, потому что их конвейеры очень глубокие.

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

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

4 голосов
/ 06 ноября 2010

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

2 голосов
/ 06 ноября 2010

Производительность зависит от компилятора и машины.Например, в моем эксперименте с gcc 4.4.5 на x64 второе было незначительно быстрее, в то время как другие сообщали, что первое было быстрее.Поэтому я рекомендую придерживаться первого, потому что оно чище (без приведения) и безопаснее (без проблем с порядком байтов).

1 голос
/ 06 ноября 2010

Я бы предложил решение с объединением:

union color { 
    // first representation (member of union) 
    struct s_color { 
        unsigned char a, b, g, r;
    } uc_color;

    // second representation (member of union) 
    unsigned int int_color; 
};

int main()
{
  color a;
  a.int_color = 0x23567899;
  a.uc_color.a;
  a.uc_color.b;
  a.uc_color.g;
  a.uc_color.r;
}

Позаботьтесь о том, чтобы он зависел от платформы (какой порядок)

1 голос
/ 06 ноября 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...