1

I'm migrating a software from Delphi 5 to Delphi XE. I've already corrected a lot of differences, and i can now compile my code.

The problem happening is that sometimes (in some places of the code), I'm getting the error "Range Check Error".

For exemple, in this code:

function CopyChar(Ori : string; var Des : Array of char) : Boolean;
var Msg     : string;
    Counter : integer;
    SizeDes : integer;
begin
    SizeDes:= SizeOf(Des);
    for Counter:= 1 to SizeDes do begin
        Des[Counter-1]:= ' ';
    end;
    Ori:= Trim(Ori);
    Msg:= '';
    SizeDes:= Min(Length(Ori),SizeDes);
    for Counter:= 1 to SizeDes do begin
        Des[Counter-1]:= char(Ori[Counter]);
    end;
    CopyChar:= True;
end;

I get the error at runtime when passing by the line Des[Counter-1] := ' '; The error occurr not at the first time it passes through the loop, but after lot of times.

I've tried to disable Rance Checking ($R) but it does nos solves my problem. I've also tried to change the type of "Counter" to Cardinal and LongWord, with no success

I would be glad for any helpful idea!

Thanks.

Marcela Rocha
  • 79
  • 2
  • 12
  • 1
    Instead of describing it as stopping after a "lot of times," be precise. Use the debugger to find out exactly how many times you get through the loop. That should have been among the *first* things you asked yourself when you saw it crash. Do all the variables have the values you expected them to? If they don't, how do they differ? Why did you expect them to have the values you did, and how did they get other values instead? – Rob Kennedy Jan 18 '11 at 15:56

2 Answers2

5

The code should read something like this:

function CopyChar(Ori : string; var Des : Array of char) : Boolean;
var Msg     : string;
    Counter : integer;
    LenDes  : integer;
begin
    LenDes:= Length(Des);
    for Counter:= 1 to LenDes do begin
        Des[Counter-1]:= ' ';
    end;
    Ori:= Trim(Ori);
    Msg:= '';
    LenDes:= Min(Length(Ori),LenDes);
    for Counter:= 1 to LenDes do begin
        Des[Counter-1]:= char(Ori[Counter]);
    end;
    CopyChar:= True;
end;

I guess your problem is to do with Char now being 2 bytes wide (in Delphi 5 it was 1 byte wide) although I have never used SizeOf on an open array and don't even know what it does!

There are a couple of other issues with this code. The return value seems a little pointless since it can only ever return True. It could also be somewhat compressed like so:

procedure CopyChar(Ori: string; var Des: array of char);
var
  i: Integer;
begin
  Ori := Trim(Ori);
  for i := 1 to Length(Des) do begin
    if i<=Length(Ori) then
      Des[i-1] := Ori[i];
    else
      Des[i-1] := ' ';
  end;
end;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 1
    You can't use a dynamic array in the above code; Des argument is a static array, and SizeOf(Des) = Length(Des) * SizeOf(Char); – kludg Jan 18 '11 at 15:32
  • @Serg My mistake, I should of course have written *open array* and I've corrected that. In fact you can pass a dynamic array to this function. – David Heffernan Jan 18 '11 at 15:37
  • No, you can't pass a dynamic array of char as an open array, at least it is impossible in Delphi 2009 - see http://stackoverflow.com/questions/3781691/is-a-dynamic-array-of-char-allowed-when-the-parameter-type-is-open-array-of-char – kludg Jan 18 '11 at 17:30
  • @Serg I stand corrected. I naively assumed that you could do this because you can do it for non-character types. I've never come across this because, naturally, I don't use open arrays of character types. – David Heffernan Jan 18 '11 at 17:34
  • Thanks, it solved the ERangeError, but I got as result strange characters (as little squares). So, I had to change all of the array of Char, replacing them by array of AnsiChar. – Marcela Rocha Jan 18 '11 at 19:00
  • @Marcela It's hard to understand what's going on here without seeing what's on the other side of CopyChar. But it seems to me that you need to do some reading up on the Unicode changes introduced in modern Delphi. Take a look at Marco Cantu's paper on the subject: http://edn.embarcadero.com/article/38980 – David Heffernan Jan 18 '11 at 19:12
  • And you might want to read up on the difference between Length(x) and Sizeof(x). Length tells you the number of elements in an array. Sizeof tells you the number of bytes in a Type. – Warren P Jan 19 '11 at 20:15
  • @Warren To quote the documentation, "Returns the number of bytes occupied by a variable or type". In this case the OP is using it on a variable rather than a type. – David Heffernan Jan 19 '11 at 20:26
2

Another problem could be a corrupted input of either Ori or Des, so if the problem is not solved by Davids solution, you should check the calling code, too.

Jens Mühlenhoff
  • 14,565
  • 6
  • 56
  • 113
  • The original problem is that SizeOf was being used instead of Length and SizeOf returns 2*Length when the array is a Char now that Char is 2 bytes wide. And why is this more efficient? – David Heffernan Jan 18 '11 at 16:45
  • Sure, but not necessarily the only problem. It is more efficient, because the comparison is not done for every loop iteration. That does not take into account what the optimizer does though, I confess that I did not read the generated assembly code ;) – Jens Mühlenhoff Jan 18 '11 at 16:48
  • 1
    It's hardly worth it considering that the code becomes harder to read and verify! It's most likely that performance will not be a bottleneck here. And in any case, your code does indeed do a comparison every loop iteration, and it doesn't terminate correctly since the < checks should be <=. So I think it won't go any faster, and it's incorrect. This is a good example of what premature optimisation does! – David Heffernan Jan 18 '11 at 17:03