как преобразовать числа с прямым порядком байтов в собственные числа delphi

Я хочу знать, как преобразовать числа с прямым порядком байтов в собственные числа в Delphi. Я портирую код C ++, с которым столкнулся:

unsigned long blockLength  = *blockLengthPtr++ << 24;
blockLength |= *blockLengthPtr++ << 16;
blockLength |= *blockLengthPtr++ << 8;
blockLength |= *blockLengthPtr;

unsigned long dataLength  = *dataLengthPtr++ << 24;
dataLength |= *dataLengthPtr++ << 16;
dataLength |= *dataLengthPtr++ << 8;
dataLength |= *dataLengthPtr;

Я не знаком с C ++, поэтому не понимаю, что делают эти операторы.


person steve0    schedule 17.06.2010    source источник
comment
возможный дубликат Как преобразовать Big Endian и как перевернуть самый высокий бит?   -  person Jeroen Wiert Pluimers    schedule 18.06.2010


Ответы (2)


Ответ Андреаса - довольно хороший пример того, как это сделать на чистом паскале, но он по-прежнему выглядит неуклюже, как и код C ++. На самом деле это можно сделать с помощью одной инструкции сборки, хотя какая из них зависит от того, используете ли вы 32-битные или 16-битные целые числа:

function SwapEndian32(Value: integer): integer; register;
asm
  bswap eax
end;

function SwapEndian16(Value: smallint): smallint; register;
asm
  rol   ax, 8
end;
person Mason Wheeler    schedule 17.06.2010
comment
Вам не нужно указывать соглашение о вызовах, по крайней мере, для Delphi (не знаю о Free Pascal). register - значение по умолчанию. - person Michael Madsen; 18.06.2010
comment
Тогда это решение! - person Andreas Rejbrand; 18.06.2010
comment
Вам не нужно указывать соглашение о вызовах, @Michael, но полезно включать его в такие функции ассемблера, поскольку они требуют определенного соглашения о вызовах для работы должным образом. - person Rob Kennedy; 18.06.2010
comment
Да, в основном то, что сказал Роб. Я знаю, что это стандартное соглашение о вызовах, и указывать register; там необязательно, но указание этого явно проясняет, почему вы работаете с регистром (E) AX. - person Mason Wheeler; 18.06.2010
comment
Это плохой пример использования директивы перегрузки, которой следует избегать. Типы Integer и SmallInt очень близки и неявно преобразуются компилятором. Вы можете сохранить значение SmallInt в переменной Integer (это обычная практика на 32-битной платформе), и вы, скорее всего, допустите ошибку, которую трудно найти с перегруженным SwapEndian. Выделенные имена (например, SwapEndian16 и SwapEndian32) более безопасны и лучше. - person kludg; 18.06.2010
comment
rol ax, 8 намного эффективнее, чем xchg на современных процессорах. Это всего лишь 1 моп, что позволяет избежать остановки (или слияния) частичного регистра при чтении AX после записи AH и AL. Это было большой проблемой, особенно на процессорах семейства Intel P6, но даже Skylake не умеет писать AH. - person Peter Cordes; 20.03.2018
comment
Вероятно, вам следует использовать Int32 вместо целого числа в 32-битной версии, поскольку - теоретически - целочисленный тип может быть любым (он был 16-битным в Delphi 1.0 и может быть 64-битным в будущей версии), тогда как Int32 всегда будет быть 32-битным. Точно так же smallint должен быть Int16 для будущей совместимости. - person HeartWare; 20.03.2018

Чтобы изменить порядок битов:

procedure SwapEndiannessOfBits(var Value: cardinal);
var
  tmp: cardinal;
  i: Integer;
begin
  tmp := 0;
  for i := 0 to 8*sizeof(Value) - 1 do
    inc(tmp, ((Value shr i) and $1) shl (8*sizeof(Value) - i - 1));
  Value := tmp;
end;

Чтобы изменить порядок байтов:

procedure SwapEndiannessOfBytes(var Value: cardinal);
var
  tmp: cardinal;
  i: Integer;
begin
  tmp := 0;
  for i := 0 to sizeof(Value) - 1 do
    inc(tmp, ((Value shr (8*i)) and $FF) shl (8*(sizeof(Value) - i - 1)));
  Value := tmp;
end;

Я думаю, что последний - это то, что вы ищете. Но, скорее всего, есть более быстрые и элегантные решения.

Отказ от ответственности: я могу ошибаться. Сейчас я немного сбит с толку. Надеюсь, кто-нибудь еще увидит этот вопрос и даст более определенный ответ!

person Andreas Rejbrand    schedule 17.06.2010