2016-07-17 6 views
-1

У меня есть указатель на массив char, и мне нужно идти и XOR каждый байт с 64-битной маской. Я думал, что самый простой способ сделать это - прочитать каждый 8 байтов как один long long или uint64_t и XOR с этим, но я не уверен, как это сделать. Может быть, листинг на long long* и разыменование? Я по-прежнему совершенно не уверен в указателях в целом, поэтому любой примерный код был бы очень оценен. Благодаря!Как читать последовательность байтов с указателя на C++ так долго?

EDIT: Пример кода (просто чтобы показать, что я хочу, я знаю, что это не работает):

void encrypt(char* in, uint64_t len, uint64_t key) { 
     for (int i = 0; i < (len>>3); i++) { 
      (uint64_t*)in ^= key; 
      in += 8; 
     } 
    } 
} 
+1

Вам нужно убедиться, что ваш символ [] правильно выровнен, если вы хотите пройти этот маршрут. Безопаснее работать по одному байту за раз, пока производительность не потребует иного. – ildjarn

+0

Пожалуйста, добавьте хотя бы пример кода [минимального] (http://stackoverflow.com/help/mcve), чтобы показать, что именно вы хотели бы достичь. Почему вам все равно нужны байты указателей XOR? – Jezor

+0

@ildjarn Я собираюсь делать это до нескольких мегабайт, поэтому производительность имеет решающее значение. :/ – TheAbelo2

ответ

3

простой способ сделать ваш XOR-маскировка байтами:

void encrypt(uint8_t* in, size_t len, const uint8_t key[8]) 
{ 
    for (size_t i = 0; i < len; i++) { 
     in[i] ^= key[i % 8]; 
    } 
} 

Примечание: здесь key представляет собой массив из 8 байтов, а не 64-разрядное число. Этот код прост - никаких трюков не требуется, их легко отлаживать. Измерьте его производительность и выполняйте его, если производительность достаточно хорошая.

Некоторые (наиболее?) Компиляторы оптимизируют такой простой код на vectorizing it. То есть все детали (отбрасывание до uint64_t и т. Д.) Выполняются компилятором. Однако, если вы пытаетесь быть «умными» в своем коде, вы можете непреднамеренно предотвратить компилятор от оптимизации. Поэтому попробуйте написать простой код.

P.S. Вероятно, вы также должны использовать ключевое слово restrict, которое в настоящее время является нестандартным, но может потребоваться для обеспечения максимальной производительности. У меня нет опыта его использования, поэтому я не добавил его к моему примеру.


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

void encrypt(uint8_t* in, size_t len, uint64_t key) 
{ 
    uint64_t* in64 = reinterpret_cast<uint64_t*>(in); 
    for (size_t i = 0; i < len/8; i++) { 
     in64[i] ^= key; 
    } 
} 

Он имеет некоторые ограничения:

  • Требуется, чтобы длина была делящейся на 8
  • Требуется, чтобы процессор поддерживал невыровненные указатели (не уверен, что о x86 - возможно, будет работать)
  • Компилятор может отказаться от вексеризации этого, что приводит к ухудшению качества работы
  • Как отмечено Hurkyl, порядок 8 байтов в маске не ясен (на x86, little-endian, младший байт будет маскировать первый байт входного массива)
+0

Что такое size_t? Я никогда раньше не сталкивался с этим. – TheAbelo2

+0

'size_t' является подходящим типом для размеров; объяснено [здесь] (http://en.cppreference.com/w/cpp/types/size_t) – anatolyg

+1

'std :: uint8_t' не является допустимым типом для чтения представления объекта, поскольку он не обязан быть символом' char типа, которые являются единственными, у которых есть такое пособие, поэтому использование его не переносится и рискует UB. Тогда ваша вторая половина - очень плохой совет и мощный эффективный генератор UB, поскольку литье _from_ 'char *' нарушает строгий псевдоним (нет симметрии с учетом литья _to_ 'char *') –