Recent

Author Topic: [SOLVED] Weird result with IntToHex(NToBE(TheSmallint), Dgt)  (Read 8945 times)

garlar27

  • Hero Member
  • *****
  • Posts: 652
[SOLVED] Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« on: January 27, 2015, 03:58:39 pm »
I was doing some test with endianness to see its hexadecimal representation and obtained weird results for SmallInt numbers > 127 and < 512.
Drop a Button and a SpinEdit to a form, and this code to the Button1.OnClick event:

Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
   LEStr, BEStr, ThisPC,
   AMsg: string;
   TheSmallInt: SmallInt;
   TheWord    : Word    ;
   TheLongInt : LongInt ;
   TheLongWord: LongWord;
   TheInt64   : Int64   ;
   TheQWord   : QWord   ;
   Dgt: integer;
begin
   AMsg := '';

   TheSmallInt := SpinEdit1.Value;
   Dgt := SizeOf(TheSmallInt)*2;
   LEStr := IntToHex(NtoLE(TheSmallInt), Dgt);
   BEStr := IntToHex(NtoBE(TheSmallInt), Dgt);
   ThisPC := IntToHex(TheSmallInt, Dgt);
   AMsg := AMsg + Format('TheSmallInt = %D; ThisPC = "$%S"; LEndian = "$%S"; BEndian ="$%S";'+LineEnding, [TheSmallInt, ThisPC, LEStr, BEStr]);


   TheWord := SpinEdit1.Value;
   Dgt := SizeOf(TheWord)*2;
   LEStr := IntToHex(NtoLE(TheWord), Dgt);
   BEStr := IntToHex(NtoBE(TheWord), Dgt);
   ThisPC := IntToHex(TheWord, Dgt);
   AMsg := AMsg + Format('TheWord = %D; ThisPC = "$%S"; LEndian = "$%S"; BEndian ="$%S";'+LineEnding, [TheWord, ThisPC, LEStr, BEStr]);


   TheLongInt := SpinEdit1.Value;
   Dgt := SizeOf(TheLongInt)*2;
   LEStr := IntToHex(NtoLE(TheLongInt), Dgt);
   BEStr := IntToHex(NtoBE(TheLongInt), Dgt);
   ThisPC := IntToHex(TheLongInt, Dgt);
   AMsg := AMsg + Format('TheLongInt = %D; ThisPC = "$%S"; LEndian = "$%S"; BEndian ="$%S";'+LineEnding, [TheLongInt, ThisPC, LEStr, BEStr]);


   TheLongWord := SpinEdit1.Value;
   Dgt := SizeOf(TheLongWord)*2;
   LEStr := IntToHex(NtoLE(TheLongWord), Dgt);
   BEStr := IntToHex(NtoBE(TheLongWord), Dgt);
   ThisPC := IntToHex(TheLongWord, Dgt);
   AMsg := AMsg + Format('TheLongWord = %D; ThisPC = "$%S"; LEndian = "$%S"; BEndian ="$%S";'+LineEnding, [TheLongWord, ThisPC, LEStr, BEStr]);


   TheInt64 := SpinEdit1.Value;
   Dgt := SizeOf(TheInt64)*2;
   LEStr := IntToHex(NtoLE(TheInt64), Dgt);
   BEStr := IntToHex(NtoBE(TheInt64), Dgt);
   ThisPC := IntToHex(TheInt64, Dgt);
   AMsg := AMsg + Format('TheInt64 = %D; ThisPC = "$%S"; LEndian = "$%S"; BEndian ="$%S";'+LineEnding, [TheInt64, ThisPC, LEStr, BEStr]);


   TheQWord := SpinEdit1.Value;
   Dgt := SizeOf(TheQWord)*2;
   LEStr := IntToHex(NtoLE(TheQWord), Dgt);
   BEStr := IntToHex(NtoBE(TheQWord), Dgt);
   ThisPC := IntToHex(TheQWord, Dgt);
   AMsg := AMsg + Format('TheQWord = %D; ThisPC = "$%S"; LEndian = "$%S"; BEndian ="$%S";'+LineEnding, [TheQWord, ThisPC, LEStr, BEStr]);


   ShowMessage(AMsg);
end;

and got this output:
Quote
TheSmallInt = 511; ThisPC = "$01FF"; LEndian = "$01FF"; BEndian ="$FFFFFF01";
TheWord = 511; ThisPC = "$01FF"; LEndian = "$01FF"; BEndian ="$FF01";
TheLongInt = 511; ThisPC = "$000001FF"; LEndian = "$000001FF"; BEndian ="$FF010000";
TheLongWord = 511; ThisPC = "$000001FF"; LEndian = "$000001FF"; BEndian ="$FF010000";
TheInt64 = 511; ThisPC = "$00000000000001FF"; LEndian = "$00000000000001FF"; BEndian ="$FF01000000000000";
TheQWord = 511; ThisPC = "$00000000000001FF"; LEndian = "$00000000000001FF"; BEndian ="$FF01000000000000";

Did you have the same problem? Or is something terribly wrong in my code?

I'm using an old Lazarus and FPC 2.6.2 on Windows.
« Last Edit: January 30, 2015, 09:32:47 pm by garlar27 »

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #1 on: January 27, 2015, 05:06:40 pm »
SmallInt is a signed type. 511 = $01FF  >  $FF01 = -255

IntToHex does not have an overloaded version that takes SmallInt.

The nearest type is Integer (4 bytes or 8 digits).

SmallInt is implicitly converted to Integer
 ($FF01 = -255)  ---> ($FFFFFF01 = -255)

The second parameter "Dgt" is irrelevant because the converted number does not fit in the number of digits passed to this version of IntToHex.

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #2 on: January 27, 2015, 07:46:46 pm »
Yes the curious thing is that it seems to work fine inside the ShortInt range (-128..127), from 128..511 it's "broken" using a 4 Bytes integer. From 512 and above it acts as expected.

Look at this:
Quote
TheSmallInt = 127; ThisPC = "$007F"; LEndian = "$007F"; BEndian ="$7F00";
TheWord = 127; ThisPC = "$007F"; LEndian = "$007F"; BEndian ="$7F00";
TheLongInt = 127; ThisPC = "$0000007F"; LEndian = "$0000007F"; BEndian ="$7F000000";
TheLongWord = 127; ThisPC = "$0000007F"; LEndian = "$0000007F"; BEndian ="$7F000000";
TheInt64 = 127; ThisPC = "$000000000000007F"; LEndian = "$000000000000007F"; BEndian ="$7F00000000000000";
TheQWord = 127; ThisPC = "$000000000000007F"; LEndian = "$000000000000007F"; BEndian ="$7F00000000000000";


TheSmallInt = 128; ThisPC = "$0080"; LEndian = "$0080"; BEndian ="$FFFF8000";
TheWord = 128; ThisPC = "$0080"; LEndian = "$0080"; BEndian ="$8000";
TheLongInt = 128; ThisPC = "$00000080"; LEndian = "$00000080"; BEndian ="$80000000";
TheLongWord = 128; ThisPC = "$00000080"; LEndian = "$00000080"; BEndian ="$80000000";
TheInt64 = 128; ThisPC = "$0000000000000080"; LEndian = "$0000000000000080"; BEndian ="$8000000000000000";
TheQWord = 128; ThisPC = "$0000000000000080"; LEndian = "$0000000000000080"; BEndian ="$8000000000000000";



TheSmallInt = 511; ThisPC = "$01FF"; LEndian = "$01FF"; BEndian ="$FFFFFF01";
TheWord = 511; ThisPC = "$01FF"; LEndian = "$01FF"; BEndian ="$FF01";
TheLongInt = 511; ThisPC = "$000001FF"; LEndian = "$000001FF"; BEndian ="$FF010000";
TheLongWord = 511; ThisPC = "$000001FF"; LEndian = "$000001FF"; BEndian ="$FF010000";
TheInt64 = 511; ThisPC = "$00000000000001FF"; LEndian = "$00000000000001FF"; BEndian ="$FF01000000000000";
TheQWord = 511; ThisPC = "$00000000000001FF"; LEndian = "$00000000000001FF"; BEndian ="$FF01000000000000";


TheSmallInt = 512; ThisPC = "$0200"; LEndian = "$0200"; BEndian ="$0002";
TheWord = 512; ThisPC = "$0200"; LEndian = "$0200"; BEndian ="$0002";
TheLongInt = 512; ThisPC = "$00000200"; LEndian = "$00000200"; BEndian ="$00020000";
TheLongWord = 512; ThisPC = "$00000200"; LEndian = "$00000200"; BEndian ="$00020000";
TheInt64 = 512; ThisPC = "$0000000000000200"; LEndian = "$0000000000000200"; BEndian ="$0002000000000000";
TheQWord = 512; ThisPC = "$0000000000000200"; LEndian = "$0000000000000200"; BEndian ="$0002000000000000";

Maybe the problem is not with "IntToHex" but with "NToBE" in my Little Endian PC.

I was playing with TCP communications and messages with its size, plus the endianness, precision (2, 4 or 8 Bytes), and if it is signed or not of it (the size bytes) .

Then the receptor of the message reported an "incomplete message received" error and looking to the server log I could see that the server was expecting a huuuuuge message when the client sent 228 bytes.
So I got this error just by chance since the messages should be much longer.-

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #3 on: January 28, 2015, 05:16:38 am »
Yes the curious thing is that it seems to work fine inside the ShortInt range (-128..127)

The rule is simple: if the resultant number after changing the endianess represents a negative number then the implicit conversion is going to change it by adding extra $FF as much as needed for the nearest available type (2 bytes for Integer in this case).

Your example:
SmallInt 127 is $007F
a-  (change endianess) -> $7F00 (which is *not* a negative number)
b-  (implicit conversion to integer) -> $00007F00 (because it is not a negative number)
c-  IntToHex gives the expected result "7F00"

When the result of changing endianess is a negative number, then we would have to add $FFFF to convert it from SmallInt to Integer and IntToHex would show that!

Another way to handle this is by doing the conversion to Integer by yourself before calling IntToHex. Instead of:
Code: [Select]
BEStr := IntToHex(NtoBE(TheSmallInt), Dgt);

do:
Code: [Select]
TheInteger := NtoBE(TheSmallInt) and $0000FFFF;
BEStr := IntToHex(TheInteger, Dgt);
This way when TheSmallInt is $XXYY then after changing its endianess it becomes $YYXX and
TheInteger := NtoBE(TheSmallInt) and $0000FFFF; would yield $0000YYXX

OR

Use unsigned types like WORD instead of SmallInt.

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #4 on: January 28, 2015, 02:40:33 pm »
Thankyou! Now I understand what went wrong.

Is good to know the workaround to those problems although I'm not going to use hexadecimal strings.

Another question:
Is there a way (a function allready made) to get the ASCII version of a number (sort of memory dump)?
for instance:

Code: [Select]
TheSmallint := 1;
AString := ValueToStr(TheSmallInt); // sets AString equals to #0#1

I made one, but I would like to know if FPC already has one. I'm not a fan of inventing the wheel which already exist (except for learning purposes, after that, I don't use the one I made).  :D

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #5 on: January 28, 2015, 07:53:25 pm »
Is there a way (a function allready made) to get the ASCII version of a number (sort of memory dump)?
for instance:

Code: [Select]
TheSmallint := 1;
AString := ValueToStr(TheSmallInt); // sets AString equals to #0#1
The example "#0#1" kinda confused me. I think you are looking for IntToStr and Format from SysUtils unit.

I made one, but I would like to know if FPC already has one. I'm not a fan of inventing the wheel which already exist (except for learning purposes, after that, I don't use the one I made).  :D
re-inventing wheels is really not that bad.

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #6 on: January 28, 2015, 09:48:45 pm »
The example "#0#1" kinda confused me. I think you are looking for IntToStr and Format from SysUtils unit.

Imeant to take it as is in memory, not a human readable interpretation of the number 1. Not in decimal nor binary neither exadecimal.
Just as it is in memory.

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #7 on: January 29, 2015, 01:20:19 am »
I see. I don't think there is a function like that within Lazarus because it takes data from GDB during debugging and it parses it. I could be wrong. If there is one I would expect it to be somewhere in Lazarus\debugger folder.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #8 on: January 29, 2015, 05:30:48 am »
Imeant to take it as is in memory, not a human readable interpretation of the number 1. Not in decimal nor binary neither exadecimal.
Just as it is in memory.
To avoid the problem described above with signed/unsigned integers, you just need to explicitly cast signed to unsigned value.
The compiler would just pass "bytes" of signed integer as unsigned (without any interpretation). Thus results should be as desired.
Code: [Select]
var
  TheSmallInt : smallint;
  Dgt: integer;
  LeStr: string;
  BeStr: string;
  ThisPC : string;
begin
  TheSmallInt := 511;
  Dgt := SizeOf(TheSmallInt)*2;
  LEStr := IntToHex(NtoLE(word(TheSmallInt)), Dgt);
  BEStr := IntToHex(NtoBE(word(TheSmallInt)), Dgt);
  ThisPC := IntToHex(Word(TheSmallInt), Dgt);
  writeln( format('TheSmallInt = %D; ThisPC = "$%S"; LEndian = "$%S"; BEndian ="$%S";', [TheSmallInt, ThisPC, LEStr, BEStr]));
end.

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #9 on: January 29, 2015, 06:43:24 pm »
To avoid the problem described above with signed/unsigned integers, you just need to explicitly cast signed to unsigned value.
The compiler would just pass "bytes" of signed integer as unsigned (without any interpretation). Thus results should be as desired.
Code: [Select]
var
  TheSmallInt : smallint;
  Dgt: integer;
  LeStr: string;
  BeStr: string;
  ThisPC : string;
begin
  TheSmallInt := 511;
  Dgt := SizeOf(TheSmallInt)*2;
  LEStr := IntToHex(NtoLE(word(TheSmallInt)), Dgt);
  BEStr := IntToHex(NtoBE(word(TheSmallInt)), Dgt);
  ThisPC := IntToHex(Word(TheSmallInt), Dgt);
  writeln( format('TheSmallInt = %D; ThisPC = "$%S"; LEndian = "$%S"; BEndian ="$%S";', [TheSmallInt, ThisPC, LEStr, BEStr]));
end.
I like that solution  :)

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #10 on: January 29, 2015, 08:19:07 pm »
And if you are going to use TheSmallInt frequently and don't like typing a lot use absolute :
Code: [Select]
var
  TheSmallInt : smallint;
  TheWord : word absolute TheSmallInt; //<---
  Dgt: integer;
  LeStr: string;
  BeStr: string;
  ThisPC : string;
begin
  TheSmallInt := 511;
  Dgt := SizeOf(TheSmallInt)*2;
  LEStr := IntToHex(NtoLE(TheWord), Dgt);
  BEStr := IntToHex(NtoBE(TheWord), Dgt);
  ThisPC := IntToHex(TheWord, Dgt);
  writeln( format('TheSmallInt = %D; ThisPC = "$%S"; LEndian = "$%S"; BEndian ="$%S";', [TheSmallInt, ThisPC, LEStr, BEStr]));
end.

O:-)

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #11 on: January 30, 2015, 09:17:27 pm »
What I need are unsigned types.

I could ignore that, but it wouldn't let me sleep well at night  :-[ .

By the way, I have a last question about "IntToHex" and "binStr":

The following code will produce the exact same output on a BigEndian PC and a LittleEndian PC or not?
Code: [Select]
Program Test;

uses system, sysutils;

var
   SomeInt: LongInt;
   SomeHexStr, SomeBinStr: string;

begin
   SomeInt := 1234;
   SomeHexStr := IntToHex(SomeInt, SizeOf(SomeInt) *2);
   SomeBinStr := binStr(SomeInt, BitSizeOf(SomeInt));

   Writeln('SomeHexStr: ', SomeHexStr);
   Writeln('SomeBinStr: ', SomeBinStr);
end.



engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #12 on: January 30, 2015, 09:22:55 pm »
Yes, sure!

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Weird result with IntToHex(NToBE(TheSmallint), Dgt)
« Reply #13 on: January 30, 2015, 09:32:12 pm »
Thankyou!!!

 

TinyPortal © 2005-2018