OberonCore
https://forum.oberoncore.ru/

Работа с байтами
https://forum.oberoncore.ru/viewtopic.php?f=2&t=267
Страница 1 из 2

Автор:  Иван Горячев [ Суббота, 08 Июль, 2006 06:11 ]
Заголовок сообщения:  Работа с байтами

Господа, помогите убогому! Требуется разбить целое на байты а потом его обратно склеить. Как разбить, понятно:
Код:
PROCEDURE SPLIT (x : INTEGER; VAR b0, b1, b2, b3 : BYTE);
BEGIN
   b0 := SHORT(SHORT(x MOD 100H));
   b1 := SHORT(SHORT(x DIV 100H));
   b2 := SHORT(SHORT(x DIV 10000H));
   b3 := SHORT(SHORT(x DIV 1000000H));
END SPLIT;

А вот со склейкой так просто не получается. Вариант:
Код:
PROCEDURE COMPOSE (b0, b1, b2, b3 : BYTE) : INTEGER;
BEGIN
   RETURN b0 + b1 * 100H + b2 * 10000H + b3 * 1000000H
END COMPOSE;
не работает, ибо тип BYTE знаковый, и плюсы местами честно превращаются в минусы :( Кроме модуля SYSTEM или страшного тега [ code ] ничего в голову не приходит, но может есть ещё варианты?

И попутный вопрос: кто-нибудь в компиляторе копался на предмет встроенных процедур? В смысле за процедурами BITS, ORD etc стоит реальный код, или они только для соблюдения строгости?

Автор:  Сергей Губанов [ Суббота, 08 Июль, 2006 16:48 ]
Заголовок сообщения:  Re: Работа с байтами

Модуль Stores:
Код:
  PROCEDURE (VAR rd: Reader) ReadInt* (OUT x: INTEGER), NEW;
    VAR le, be: ARRAY 4 OF BYTE;  (* little endian, big endian *)
  BEGIN
    rd.rider.ReadBytes(le, 0, 4);
    IF Kernel.littleEndian THEN
      x := SYSTEM.VAL(INTEGER, le)
    ELSE
      be[0] := le[3]; be[1] := le[2]; be[2] := le[1]; be[3] := le[0];
      x := SYSTEM.VAL(INTEGER, be)
    END
  END ReadInt;


Код:
  PROCEDURE (VAR wr: Writer) WriteInt* (x: INTEGER), NEW;
    TYPE a = ARRAY 4 OF BYTE;
    VAR le, be: a;  (* little endian, big endian *)
  BEGIN
    IF Kernel.littleEndian THEN
      le := SYSTEM.VAL(a, x)
    ELSE
      be := SYSTEM.VAL(a, x);
      le[0] := be[3]; le[1] := be[2]; le[2] := be[1]; le[3] := be[0]
    END;
    wr.rider.WriteBytes(le, 0, 4)
  END WriteInt;

Автор:  Сергей Оборотов [ Воскресенье, 09 Июль, 2006 00:36 ]
Заголовок сообщения: 

Можно и так.
Код:
PROCEDURE COMPOSE (b0, b1, b2, b3 : BYTE) : INTEGER;
VAR i:INTEGER;
BEGIN
   i := b3 MOD 100H;
   i := ASH(i,8)+b2 MOD 100H;
   i := ASH(i,8)+b1 MOD 100H;
   i := ASH(i,8)+b0 MOD 100H;
   RETURN i
END COMPOSE;

Процедуры ORD и BITS влияют на обработку выражений в компиляторе.

Автор:  Илья Ермаков [ Воскресенье, 09 Июль, 2006 15:12 ]
Заголовок сообщения: 

Нет, так нельзя. Сложение целых использовать для побитных операций нельзя, т.к. целые знаковые - на старшем байте все равно сложение превратится в вычитание.

Можно так:
Код:
   i := BITS(b3)*{0..7} + BITS(ASH(b2, 8))*{8..15} +
         BITS(ASH(b1, 16))*{16..23} + BITS(ASH(b0, 24))*{24..31}

Автор:  Сергей Оборотов [ Понедельник, 10 Июль, 2006 07:14 ]
Заголовок сообщения: 

Согласен.
Код:
PROCEDURE COMPOSE (b0, b1, b2, b3 : BYTE) : INTEGER;
VAR i:INTEGER;
BEGIN
   i := ORD(BITS(b3)*{0..7});
   i := ORD(BITS(ASH(i,8))+BITS(b2)*{0..7});
   i := ORD(BITS(ASH(i,8))+BITS(b1)*{0..7});
   i := ORD(BITS(ASH(i,8))+BITS(b0)*{0..7});
   RETURN i
END COMPOSE;
Хотя первые три присваивания можно было и не менять.

Автор:  Иван Горячев [ Понедельник, 10 Июль, 2006 07:46 ]
Заголовок сообщения: 

Очевидно, можно и так:
Код:
PROCEDURE COMPOSE (b0, b1, b2, b3 : BYTE) : INTEGER;
BEGIN
   RETURN SHORT(ORD(BITS(b0)) + ORD(BITS(b1)) * 100L + ORD(BITS(b2)) * 10000L + ORD(BITS(b3)) * 1000000L)
END COMPOSE;

этот вариант точно от машинного представления не зависит, хотя уродец тот ещё.

Автор:  Trurl [ Понедельник, 10 Июль, 2006 10:44 ]
Заголовок сообщения: 

А мне все же больше нравиться
Код:
PROCEDURE COMPOSE (b0, b1, b2, b3 : BYTE) : INTEGER;
BEGIN
   RETURN b0 MOD 100H + b1 MOD 100H * 100H + b2 MOD 100H * 10000H + b3 MOD 100H * 1000000H
END COMPOSE;

Автор:  Иван Горячев [ Понедельник, 10 Июль, 2006 10:48 ]
Заголовок сообщения: 

На самом деле я применил страшное слово "[code]". Зато хоть с ассемблером познакомился :)

Автор:  Trurl [ Понедельник, 10 Июль, 2006 10:55 ]
Заголовок сообщения: 

Ivor писал(а):
Очевидно, можно и так:
Код:
PROCEDURE COMPOSE (b0, b1, b2, b3 : BYTE) : INTEGER;
BEGIN
   RETURN SHORT(ORD(BITS(b0)) + ORD(BITS(b1)) * 100L + ORD(BITS(b2)) * 10000L + ORD(BITS(b3)) * 1000000L)
END COMPOSE;

этот вариант точно от машинного представления не зависит, хотя уродец тот ещё.


Кажется, так нельзя. Ведь ORD(BITS(b0)) = b0 и приходим к тому, с чего начинали.

Автор:  Сергей Губанов [ Понедельник, 10 Июль, 2006 12:15 ]
Заголовок сообщения: 

Trurl писал(а):
PROCEDURE COMPOSE (b0, b1, b2, b3 : BYTE) : INTEGER;
Кажется, так нельзя. Ведь ORD(BITS(b0)) = b0 и приходим к тому, с чего начинали.

Объявите так: PROCEDURE COMPOSE (b0, b1, b2, b3 : INTEGER) : INTEGER;

-----

На самом деле байты внутри int - это ерунда.

Вот биты внутри байта - это гораздо круче! На счёт битов в байте есть страшная тайна. Оказывается они (в x86) идут наоборот! То есть если передавать биты по сети, то сначала надо отправить вовсе не 0-вой бит, а 7-мой, потом 6-той и т.д.

Вот, например, стандарт передачи битов по сети в заголовке RTP-пакета: http://rfc.net/rfc1889.html#s5.1 Там написано, что в 0 и 1 битах заголовка передается версия. По наивности (раз она в 0 и 1 битах) можно было бы попытаться узнать версию так:
this.version = (this.datagram[0] & 3);
и это, оказывается, не правильно; а правильно так:
this.version = (this.datagram[0] >> 6) & 3;
:evil: :evil: :evil:
Говорят, что все имплементаторы всяких сетевых протоколов на этом обязательно всегда накалываются. Вот и я тоже накололся по первому разу.

Автор:  Сергей Оборотов [ Понедельник, 10 Июль, 2006 17:20 ]
Заголовок сообщения: 

Вариант A:
Код:
   movsx   eax, [ebp+arg_C]
   and   eax, 0FFh
   mov   [ebp+var_4], eax
   shl   eax, 8
   movsx   edx, [ebp+arg_8]
   and   edx, 0FFh
   add   eax, edx
   mov   [ebp+var_4], eax
   shl   eax, 8
   movsx   edx, [ebp+arg_4]
   and   edx, 0FFh
   add   eax, edx
   mov   [ebp+var_4], eax
   shl   eax, 8
   movsx   edx, [ebp+arg_0]
   and   edx, 0FFh
   add   eax, edx

Вариант B:
Код:
   movsx   eax, [ebp+arg_C]
   and   eax, 0FFh
   mov   [ebp+var_4], eax
   shl   eax, 8
   movsx   edx, [ebp+arg_8]
   and   edx, 0FFh
   or   eax, edx
   mov   [ebp+var_4], eax
   shl   eax, 8
   movsx   edx, [ebp+arg_4]
   and   edx, 0FFh
   or   eax, edx
   mov   [ebp+var_4], eax
   shl   eax, 8
   movsx   edx, [ebp+arg_0]
   and   edx, 0FFh
   or   eax, edx
.
Кто скажет что это не одно и тоже?
P.S. Тест на конформизм не прохожу, однако.

Автор:  Иван Горячев [ Вторник, 11 Июль, 2006 07:16 ]
Заголовок сообщения: 

Trurl писал(а):
Кажется, так нельзя. Ведь ORD(BITS(b0)) = b0 и приходим к тому, с чего начинали.

Можно. BITS(b0) преобразует байт в SET побитово, знак не учитывается. При обратном преобразовании получаем INTEGER, у которого младший байт = b0

Автор:  Trurl [ Вторник, 11 Июль, 2006 08:03 ]
Заголовок сообщения: 

Ivor писал(а):
BITS(b0) преобразует байт в SET побитово, знак не учитывается. При обратном преобразовании получаем INTEGER, у которого младший байт = b0

BITS преобразует INTEGER в SET. А перед этим надо байт привести к целому.

Автор:  Иван Горячев [ Вторник, 11 Июль, 2006 09:02 ]
Заголовок сообщения: 

Да, действительно :?
В этом случае нужно делать так:
Код:
PROCEDURE [ code ] CARD* (x : BYTE) : INTEGER;

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

Автор:  Иван Горячев [ Вторник, 11 Июль, 2006 09:10 ]
Заголовок сообщения: 

А зачем так много?
Код:
PROCEDURE [ code ] COMPOSE (b0, b1, b2, b3 : BYTE) : INTEGER
59H,             (* POP cx      *)
88H, 0CDH,       (* MOV ch, cl  *)
88H, 0C1H,       (* MOV cl, al  *)
5AH,             (* POP dx      *)
88H, 0D0H,       (* MOV al, dl  *)
5AH,             (* POP dx      *)
88H, 0D4H,       (* MOV ah, dl  *)
0C1H, 0E0H, 10H, (* SHL eax, 16 *)
09H, 0C8H;       (* OR eax, ecx *)

Автор:  Trurl [ Вторник, 11 Июль, 2006 09:51 ]
Заголовок сообщения: 

Ivor писал(а):
Код:
PROCEDURE [ code ] CARD* (x : BYTE) : INTEGER;

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

Все же тело лучше добавить (MOVZXB EAX,AL). Иначе можно долго разбираться с мусором в старших битах.

Автор:  Сергей Оборотов [ Среда, 12 Июль, 2006 13:47 ]
Заголовок сообщения: 

Ivor писал(а):
А зачем так много?
Код:
PROCEDURE [ code ] COMPOSE (b0, b1, b2, b3 : BYTE) : INTEGER
59H,             (* POP cx      *)
88H, 0CDH,       (* MOV ch, cl  *)
88H, 0C1H,       (* MOV cl, al  *)
5AH,             (* POP dx      *)
88H, 0D0H,       (* MOV al, dl  *)
5AH,             (* POP dx      *)
88H, 0D4H,       (* MOV ah, dl  *)
0C1H, 0E0H, 10H, (* SHL eax, 16 *)
09H, 0C8H;       (* OR eax, ecx *)
Не хотелось связываться со встроенным ассемблером, поскольку его отладка затруднительна. Над указанной процедурой ещё немного поработать необходимо.
P.S. Мы верим в мужество отчаянных парней?

Автор:  Иван Горячев [ Четверг, 13 Июль, 2006 02:17 ]
Заголовок сообщения: 

GUEST писал(а):
P.S. Мы верим в мужество отчаянных парней?


Просто надоели бесконечные SYSTEM.VAL, да и я не уверен, что все эти преобразования не добавляют дополнительного кода. А вообще - почему бы и нет?
Хотя лучше сделали бы именно встроенный ассемблер. Процедуры в кодах это уж слишком круто.

Автор:  Сергей Оборотов [ Четверг, 13 Июль, 2006 12:10 ]
Заголовок сообщения: 

Цитата:
я не уверен, что все эти преобразования не добавляют дополнительного кода. А вообще - почему бы и нет?

Просто иногда дополнительный код ох как необходим. Нашли его? Или не искали?

Автор:  Иван Горячев [ Пятница, 14 Июль, 2006 01:09 ]
Заголовок сообщения: 

Не искал. Свою задачу я решил, а на отстранённые исследования времени жалко.

Страница 1 из 2 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/