Советы по Delphi

Байтовый своппинг


Ознакомьтесь в файле помощь Delphi с функцией Swap. Но там в определении есть опечатка, правильно будет так:

    function Swap(X) : word;

Ниже приведен пример использования:

   

var
X: Word; begin
X := Swap($1234);   { $3412 } end;

на первый взгляд ничего сложного.

Для своппинга 16-битного целого или слова, используйте следующий код:

    value: integer; value := swap(value); {внутренняя паскалевская функция}

Для свапирования 32-битного длинного целого:

    value: longint; value := swap(value shr 16) or (longint(swap(value and $ffff)) shl 16);

Я не знаю какие стандарты используются для значений с плавающей точкой, но если они соответствуют типам integer и longint (это моя догадка), то можно воспользоваться следующим кодом (для double):

    value: double; block: array[0..7] of byte absolute value; temp:  byte;
for i := 0 to 3 do begin temp := block[i]; block[i] := block[7-i]; block[7-i] := temp; end;

При использовании типа real массив должен быть 0..5 и цикл от 0 до 2; при использовании типа comp, 0..7 и от 0 до 3; для single 0..3 и от 0 до 1; для extended 0..9 и от 0 дo 4.

Вы можете переделать это в процедуру, которая получает указатель на значение и его размер, например (возможно нуждается в оптимизации и улучшении):

    procedure swapper (valin: pointer; size: integer); var i: integer; temp: byte; val:  ^byte; begin size := size - 1; val := valin; for i := 0 to (size div 2) do begin temp := val[i]; val[i] := val[size-i]; val[size-i] := temp; end; end;

и затем так использовать это:

    swapper (@value, sizeof(value));

(Это должно работать для longint, integer и пр., но swap() более эффективен.)

Обратите внимание на то, что дополнительно к своппингу байтов, вы можете делать преобразование формата (например, из Microsoft floating point в ANSI); я не знаком глубоко с темой чисел с плавающей точкой, поэтому эту тему я опущу. Качественной проверкой может служить сдиг байтов и проверку получившегося значения на другой системе, признающей формат чисел, обрабатываемый Delphi.

...у меня была аналогичная проблема: я считывал с диска TColor в формате RGB ($RRGGBB), тогда как delphi пользуется форматом BGR.

Я решил свою проблему and'ингом начального числа с маской, извлекая этим необходимые значения и "устанавливая" их в мой формат. Вот так:

    color := $F03200;
r := (color and $FF0000) div $010000; {должно возвратить $F0}
g := (color and $00FF00) div $000100; {должно возвратить $32}
b := (color and $0000FF);             {должно возвратить $00}
newcolor := (b * $010000) + (g * $000100) + b;

Если это сработает, то newcolor должен содержать $0032F0.

Вы можете использовать процедуру, написанную на языке ассемблер. Например, такую:

    var
result : byte;
asm {
mov cx,8 mov ah,0 mov al,<БАЙТ В ФОРМАТ BIG ENDIAN FORMAT> @do_loop
shr al,1 shl ah,1 jcc @dont_set_bit  ; просто осуществляем переход (правда, я не уверен что это правильно) xor ah,1 @dont_set_bit:
loop do_loop mov result,al }

Это скорее псевдо-код (поскольку мой ассемблер сильно хромает). Если вы хотите, чтобы код был более "портативным", то воспользуйтесь вместо inline-ассемблера паскалем (где можно использовать SHL - смещения бит налево и SHR - направо). [001970]



Содержание раздела