Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

Author Topic: [solved] How to create a signed integer from bytes  (Read 787 times)

Muso

• Jr. Member
• Posts: 90
[solved] How to create a signed integer from bytes
« on: April 15, 2021, 05:16:22 pm »
I am stuck with a simple task: create a signed 16 bit integer from two bytes. I have this code since I think one must simply combine the two bytes:

Code: Pascal  [Select][+][-]
1. var
2.  byte1, byte2 : Byte;
3.  tempInt16 : Int16;
4.
5. procedure test;
6. begin
7.  byte1:= 200;
8.  byte2:= 255;
9.  tempInt16:= (byte1 shl 8) + byte2;
10. end;

But this code raises a range exception. Why?
When the hi-byte is larger than 127 the exception is raised but since Int16 is a signed integer, I don't understand this.

How is the signed integer creation done correctly? (I googled already around without success.)
« Last Edit: April 15, 2021, 07:43:31 pm by Muso »

y.ivanov

• Jr. Member
• Posts: 95
Re: How to create a signed integer from bytes
« Reply #1 on: April 15, 2021, 05:37:09 pm »
Perhaps it is too big to fit into -32768..32767 range (it is unsigned). Use Int16() typecast.

Muso

• Jr. Member
• Posts: 90
Re: How to create a signed integer from bytes
« Reply #2 on: April 15, 2021, 05:38:50 pm »
Hmm, I tried now a simple cast and this worked:

Code: Pascal  [Select][+][-]
1. var
2.      byte1, byte2 : Byte;
3.      tempInt16 : Int16;
4.      HiLowArray : array[0..1] of Byte;
5.
6.     procedure test;
7.     begin
8.      byte1:= 200;
9.      byte2:= 255;
10.      HiLowArray[0]:= byte2;
11.      HiLowArray[1]:= byte1;
12.      tempInt16:= Int16(HiLowArray);
13.     end;

I would still like to understand why my initial attempt failed.

y.ivanov

• Jr. Member
• Posts: 95
Re: How to create a signed integer from bytes
« Reply #3 on: April 15, 2021, 05:42:48 pm »
200*256+255=51455, which is greater than 32767

Code: [Select]
`tempInt16 := Int16((byte1 shl 8) + byte2);`
« Last Edit: April 15, 2021, 05:44:33 pm by y.ivanov »

howardpc

• Hero Member
• Posts: 3694
Re: How to create a signed integer from bytes
« Reply #4 on: April 15, 2021, 05:49:32 pm »
Mixing signed (Int16) and unsigned (Byte) generally leads to trouble.
Try this:
Code: Pascal  [Select][+][-]
1. program Project1;
2.
3. {\$mode objfpc}{\$H+}
4.
5. var
6.  byte1 : Byte;
7.  tempInt16 : Int16;
8.
9. procedure test;
10. begin
11.  byte1:= 127;
12.  tempInt16 := (byte1 shl 8);
13.  WriteLn('127 in binary is ',BinStr(127, 16));
14.  WriteLn('128 in binary is ',BInStr(128, 16));
15.
16.  WriteLn('127 shifted by 8 is ',BinStr(tempInt16, 16));
17.  WriteLn('128 shifted by 8 is ',BinStr(128 shl 8, 16));
18.  WriteLn('High(Int16) as binary is ',BinStr(High(Int16), 16));
19. end;
20.
21. begin
22.   test;
23. end.

Muso

• Jr. Member
• Posts: 90
Re: How to create a signed integer from bytes
« Reply #5 on: April 15, 2021, 06:12:05 pm »
200*256+255=51455, which is greater than 32767

But this is what I don't understand. 200 > 127, so the sign bit is 1. Thus, as the two bytes represent a signed int, I should get a negative value: -14081

But my clarification that the two bytes represent a signed, not an unsigned int is ignored.
« Last Edit: April 15, 2021, 06:13:36 pm by Muso »

y.ivanov

• Jr. Member
• Posts: 95
Re: How to create a signed integer from bytes
« Reply #6 on: April 15, 2021, 06:25:43 pm »
200*256+255=51455, which is greater than 32767

But this is what I don't understand. 200 > 127, so the sign bit is 1. Thus, as the two bytes represent a signed int, I should get a negative value: -14081

But my clarification that the two bytes represent a signed, not an unsigned int is ignored.

You must put that clarification to the compiler, not to me

So, byte1 and byte2 are of type byte which is unsigned.
Expression  (byte1 shl 8 ) + byte2 which is equal to 51455, will be widened to some unsigned type, I don't know exactly which, may be Word with range 0..65535 instead of 32768..32767 and thus the assignment of 51455 to Int16 is incorrect since it cannot hold such a big value. That's it.

howardpc

• Hero Member
• Posts: 3694
Re: How to create a signed integer from bytes
« Reply #7 on: April 15, 2021, 06:29:18 pm »
The compiler simply does what you tell it do.
You tell it to shift the value of byte1 by 8.

When byte1 is greater than 127 (decimal) the expression
Code: Pascal  [Select][+][-]
1. (byte1 shl 8)
is too large to fit in a signed 16 bit integer, and so the compiler warns you of that fact if range checks are enabled.
It is as simple as that.

y.ivanov

• Jr. Member
• Posts: 95
Re: How to create a signed integer from bytes
« Reply #8 on: April 15, 2021, 06:36:26 pm »
@howardpc
Do you know where the FPC widening rules for expressions are described, since I can't find them in https://freepascal.org/docs-html/ref/ref.html. May be I'm not looking at the right place.

Thanks,

NickyTi

• Newbie
• Posts: 3
Re: How to create a signed integer from bytes
« Reply #9 on: April 15, 2021, 06:58:20 pm »
Try this

type
Tbytes2int16 = packed record
case integer of
0: (byte2, byte1 : Byte);
1: (tempInt16 : Int16);
end;

TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
bytes2int16: Tbytes2int16;
public

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
bytes2int16.byte1:=200;
bytes2int16.byte2:=255;
ShowMessage(IntToStr(bytes2int16.tempInt16));
//or
ShowMessage(bytes2int16.tempInt16.ToString);
end;

MarkMLl

• Hero Member
• Posts: 2486
Re: How to create a signed integer from bytes
« Reply #10 on: April 15, 2021, 07:13:02 pm »
type
Tbytes2int16 = packed record
case integer of
0: (byte2, byte1 : Byte);
1: (tempInt16 : Int16);
end;

That is the classic way of doing it, and avoids much grief particularly when when starts messing about with 64-bit words.

But beware of endianness issues.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

NickyTi

• Newbie
• Posts: 3
Re: How to create a signed integer from bytes
« Reply #11 on: April 15, 2021, 07:19:27 pm »
MarkMLl,
I agree with you.
It would be more correct to write;

TLoHiWord = packed record
case integer of
0: (Lower, Lo, Hi, Higher: byte);
1: (WordLo, WordHi: word);
2: (aInt: Integer);
3: (Str: array[0..3] of char);
end;

y.ivanov

• Jr. Member
• Posts: 95
Re: How to create a signed integer from bytes
« Reply #12 on: April 15, 2021, 07:23:49 pm »
But beware of endianness issues.

IMHO,
Code: Pascal  [Select][+][-]
1. tempInt16 := Int16((byte1 shl 8) + byte2)

has no chance to get the endianness wrong.

Muso

• Jr. Member
• Posts: 90
Re: How to create a signed integer from bytes
« Reply #13 on: April 15, 2021, 07:43:18 pm »
When byte1 is greater than 127 (decimal) the expression
Code: Pascal  [Select][+][-]
1. (byte1 shl 8)
is too large to fit in a signed 16 bit integer, and so the compiler warns you of that fact if range checks are enabled.
It is as simple as that.

Well, that was not clear to me and its not documented as such. I have 16 bits and Int16 has 16 bit, so it should fit in.

However, I learned now that one has take care in a different was about the sign bit. Many thanks for all your help.

NickyTi

• Newbie
• Posts: 3
Re: [solved] How to create a signed integer from bytes
« Reply #14 on: April 15, 2021, 08:10:34 pm »
Muso,
try reverse

type
Tbytes2int16 = packed record
case integer of
0: (byte2, byte1 : Byte);
1: (tempInt16 : Int16);
end;

TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
bytes2int16: Tbytes2int16;
public

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
bytes2int16.tempInt16:=-14081;
ShowMessage('byte1 = '+IntToStr(bytes2int16.byte1));
ShowMessage('byte2 = '+IntToStr(bytes2int16.byte2));
end;