[Solved] Unexpected ERangeError:Range check error lazarus / 21-General ---------------------------------------------------------------------- Wilko500 · 2024-11-15 22:43 I have just started my first foray into serial comms using LazSerial/SynaSer.  I anticipate that there may well be questions on that later. For now though I need to compute a checksum for a returned Byte array and have created a function to achieve that.  It works as expected, or at least it did until I changed from release mode to debug mode (including the range check option) when I started getting range check error that I was not expecting because the function was working. I suspect my lack of experience caused me to incorrectly(?) search for a coding error that is not there. Variables tmp and new are both of type Byte Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i       tmp:=new << 4;        //<< ERangeError:Range check error I have solved the problem by the addition of compiler directives to turn off range checks for this function. However I would like to understand why this range check error is reported.  Perhaps someone can enlighten me. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function TestChkSum(b:Array Of Byte): Int32;Var  i:               Int32;   //Loop counter  l:               Int32;   //Length of supplied byte array  BccLow, BccHigh: Byte;    //Low ond high checksum bytes  tmp, new:        Byte;    //Work vars for checksum calculation  Res:           Int32;   //Holder for function result codeBeginTry{$RangeChecks OFF}  Res:=0;  //assume good checksum  BccLow:=$ff;  BccHigh:=$ff;  l:=Length(b);  For i:= 0 to l-3 Do     //byte aray zero based and not checking last 2 bytes      Begin      new:=b[i];      new:=new xor BccLow;      tmp:=new << 4;        //<< ERangeError:Range check error      new:=tmp xor new;      tmp:=new >> 5;      BccLow:=BccHigh;      BccHigh:=new xor tmp;      tmp:=new << 3;        //<< ERangeError:Range check error      BccLow:=BccLow xor tmp;      tmp:= new >> 4;      BccLow:=BccLow xor tmp;  End;{For}  BccLow:=Not BccLow;  BccHigh:=Not BccHigh;  //Test if provided checksum matches computed value  If (b[6] <> BccLow) Or (b[7] <> BccHigh) Then      //No, checksum test failed      Begin      Res:=1  End;{If}  Result:=Res;{$RangeChecks ON}Except  On E: Exception Do  Begin  WriteLn('Exception in TestChkSum: ' + E.ClassName + ':' + E.Message);  Result:=1;  End;End;{Try}End;{Function TestChkSum} ---------------------------------------------------------------------- TRon · 2024-11-15 22:54 If you shift bits (out) of a certain type tyhen the answer will not fit into the same type anymore. Cast the answer of your shifts to a byte (or and it off) and you should be good to go. ---------------------------------------------------------------------- jamie · 2024-11-15 23:07 Must be some broken compilers out there recently? I've been seeing this sort of issue with the recent release of Lazarus, but I am still at Lazarus 3.4, and I just tested that code and works just fine here with Lazarus 3.4-Fpc 3.2.2 If you wrap the expression with a Byte, that should also work but really, turning off the Range check in mid-stream should also work. It works here, but obviously not there. I am on Windows. ---------------------------------------------------------------------- TRon · 2024-11-15 23:14 No idea what you are talking about jamie. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   writeln(sizeof($f shl 1));  writeln(sizeof($ff shl 1));  writeln(sizeof($ffff shl 1));  writeln(sizeof($ffffffff shl 1));  Code: [Select]1 2 4 8 ---------------------------------------------------------------------- Wilko500 · 2024-11-15 23:16 Quote from: TRon on November 15, 2024, 11:54:12 pmIf you shift bits (out) of a certain type then the answer will not fit into the same type anymore. Ah!  I realise that but I always thought that the shifted bits were ignored if they shifted out of the byte being shifted.  This is presumably what happens with shift right which does not error. This worked. Thank you. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i       tmp:=(new << 4) AND $FF; ---------------------------------------------------------------------- Wilko500 · 2024-11-15 23:24 Just for the record I'm using FPC 3.2.3 Lazarus 3.5 (on MacOs) at the moment installed by fpcupdeluxe fixes. ---------------------------------------------------------------------- TRon · 2024-11-15 23:24 Quote from: Wilko500 on November 16, 2024, 12:16:25 amAh!  I realise that but I always thought that the shifted bits were ignored if they shifted out of the byte being shifted.  This is presumably what happens with shift right which does not error. Indeed. It requires a bit of thought. I always think of it as shift left is multiply (number becomes bigger) and shift right is divide (number becomes smaller). The latter will still fit though perhaps in a smaller type (in your case there isn't anything smaller than a byte) while the former /might/ not fit into the same type anymore (it depends on what bits where set in the byte and how many times those bits where shifted). When doing shifts or checksum related work always make sure to cast (or what you did and off) the result so that it will still fit into the destination type. ---------------------------------------------------------------------- jamie · 2024-11-15 23:25 Looks like hack to me Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ByteResults := Byte(New << 4);   The compiler always tries to elevate the expression to an integer.  You know, the Delphi compiler handles this correctly, you don't know this crap. ---------------------------------------------------------------------- TRon · 2024-11-15 23:30 Quote from: jamie on November 16, 2024, 12:25:57 am You know, the Delphi compiler handles this correctly, you don't know this crap. Thank you very much for that confirmation. I wasn't sure. * TRon throws some carry flags around ---------------------------------------------------------------------- Wilko500 · 2024-11-15 23:37 Quote from: TRon on November 16, 2024, 12:24:52 amWhen doing shifts or checksum related work always make sure to cast (or what you did and off) the result so that it will still fit into the destination type. This function to calculate checksum was my first use of both checksums and shifting. So today I learned something new.  Should serve me well in my current project which will have lots of manipulating and decoding byte arrays.  I am attempting to create a MacOS version of Aurora Communicator (only available on Windows) to offload solar data from my inverter via RS485 serial coms. ---------------------------------------------------------------------- TRon · 2024-11-16 00:02 @Wilko500 I do hope it serves you well indeed (for sure sound like it and seem like an interesting project going on there). You know that some don't even bother with checks and just publish their code that way ? Because why should someone bother when you can turned off the checks for certain parts of your code (that are known to be wrong). ---------------------------------------------------------------------- PascalDragon · 2024-11-16 13:23 Quote from: jamie on November 16, 2024, 12:25:57 amYou know, the Delphi compiler handles this correctly, you don't know this crap. Did you even try with range checks enabled? I just tested with Delphi 10.2: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program trangechk; {$R+} uses  SysUtils; var  b1, b2: Byte;begin  b1 := $FF;  try    b2 := b1 shl 4;  except    on e: Exception do      Writeln(e.ClassName, ': ', e.Message);  end;  b2 := Byte(b1 shl 4);  Writeln(IntToHex(b2, 2));end. Output: Code: [Select]ERangeError: Fehler bei Bereichsprüfung F0 The main point is that (Object) Pascal does not determine the result of an expression based on the left side of an assignment (with only two exceptions for this: assignment of overloaded functions to function pointers and determining which assignment operator is called). This is true for both FPC and Delphi. Note: with range checks disabled this will also run without error in FPC.