Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2009-06

QWord/UInt64 and Range Check Errors

15 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Ruediger Hahn

Hi all,

I am just wondering if this is a bug: Can anyone tell me why I get a "range check error while evaluating constants" with the following simple program:

<code>
program Project1;
const
 MyVar : UInt64 = $FFFFFFFFFFFFFFFF; // 4 x 2 Bytes or 4 Words
begin
end.
</code>

In Delphi this compiles without warnings/errors even with range checking enabled.

Ruediger

Jonas Maebe
to Ruediger Hahn
Ruediger Hahn wrote 13 lines
I am just wondering if this is a bug: Can anyone tell me why I get a "range check error while evaluating constants" with the following simple program: <code> program Project1; const MyVar : UInt64 = $FFFFFFFFFFFFFFFF; // 4 x 2 Bytes or 4 Words begin end. </code>

The reason is that $FFFFFFFFFFFFFFFF is parsed as an int64 by FPC. As a result it equals -1, and -1 is not a valid uint64 value.

Jonas

Inoussa OUEDRAOGO
to Jonas Maebe

2009/6/25 Jonas Maebe :

Show quoted text 19 lines
On 25 Jun 2009, at 19:58, Ruediger Hahn wrote: > I am just wondering if this is a bug: Can anyone tell me why I get a > "range check error while evaluating constants" with the following simple > program: > > <code> > program Project1; > > const > MyVar : UInt64 = $FFFFFFFFFFFFFFFF; // 4 x 2 Bytes or 4 Words > > begin > end. > </code> The reason is that $FFFFFFFFFFFFFFFF is parsed as an int64 by FPC. As a result it equals -1, and -1 is not a valid uint64 value.

This warning is actually misleading as it makes one doubtfull about the correctness of the program( In my case I debugged the program to be sure that the "good" value was assigned).

Best regards.

Inoussa O.
Jonas Maebe
to Inoussa OUEDRAOGO
Inoussa OUEDRAOGO wrote 24 lines
2009/6/25 Jonas Maebe : > > On 25 Jun 2009, at 19:58, Ruediger Hahn wrote: > >> I am just wondering if this is a bug: Can anyone tell me why I get a >> "range check error while evaluating constants" with the following >> simple >> program: >> >> <code> >> program Project1; >> >> const >> MyVar : UInt64 = $FFFFFFFFFFFFFFFF; // 4 x 2 Bytes or 4 Words >> >> begin >> end. >> </code> > > The reason is that $FFFFFFFFFFFFFFFF is parsed as an int64 by FPC. > As a > result it equals -1, and -1 is not a valid uint64 value. This warning is actually misleading

Not warning would be misleading (and wrong).

as it makes one doubtfull about the correctness of the program( In my case I debugged the program to be sure that the "good" value was assigned).

When it's changed, you will get the warning/error when assigning this value to an int64 and then those cases can be debugged. It's the same when we changed from parsing $80000000-$FFFFFFFF as a longint to parsing it as a cardinal. Suddenly a whole bunch of code no longer worked correctly anymore then either, and we got a bunch of questions why code no longer compiled or produced warnings.

Jonas

Inoussa OUEDRAOGO
to Jonas Maebe

2009/6/25 Jonas Maebe :

Show quoted text 34 lines
On 25 Jun 2009, at 20:14, Inoussa OUEDRAOGO wrote: > 2009/6/25 Jonas Maebe : >> >> On 25 Jun 2009, at 19:58, Ruediger Hahn wrote: >> >>> I am just wondering if this is a bug: Can anyone tell me why I get a >>> "range check error while evaluating constants" with the following simple >>> program: >>> >>> <code> >>> program Project1; >>> >>> const >>> MyVar : UInt64 = $FFFFFFFFFFFFFFFF; // 4 x 2 Bytes or 4 Words >>> >>> begin >>> end. >>> </code> >> >> The reason is that $FFFFFFFFFFFFFFFF is parsed as an int64 by FPC. As a >> result it equals -1, and -1 is not a valid uint64 value. > > This warning is actually misleading Not warning would be misleading (and wrong). > as it makes one doubtfull about > the correctness of the program( In my case I debugged the program to > be sure that the "good" value was assigned). When it's changed, you will get the warning/error when assigning this value to an int64 and then those cases can be debugged.

and that seems more accurate to me

Show quoted text 5 lines
to an int64 and then those cases can be debugged. It's the same when we changed from parsing $80000000-$FFFFFFFF as a longint to parsing it as a cardinal. Suddenly a whole bunch of code no longer worked correctly anymore then either, and we got a bunch of questions why code no longer compiled or produced warnings.

IMHO warnings/errors should be reported as one is actually in a "out of range" case. But if some code depends on this ( such as a bit mask ) changing the behavior of the compiler can effectively be harmfull. I think that should be up to the people (ab)using the parser this way to correct their code by doing a explicit typecast.

Inoussa O.
Jonas Maebe
to Inoussa OUEDRAOGO
Inoussa OUEDRAOGO wrote 13 lines
2009/6/25 Jonas Maebe : > > On 25 Jun 2009, at 20:14, Inoussa OUEDRAOGO wrote: > >> as it makes one doubtfull about >> the correctness of the program( In my case I debugged the program to >> be sure that the "good" value was assigned). > > When it's changed, you will get the warning/error when assigning > this value > to an int64 and then those cases can be debugged. and that seems more accurate to me

It's equally accurate. A hex number does not contain any sign information, so both interpretations are valid.

Show quoted text 15 lines
> to an int64 and then those cases can be debugged. It's the same > when we > changed from parsing $80000000-$FFFFFFFF as a longint to parsing it > as a > cardinal. Suddenly a whole bunch of code no longer worked correctly > anymore > then either, and we got a bunch of questions why code no longer > compiled or > produced warnings. IMHO warnings/errors should be reported as one is actually in a "out of range" case. But if some code depends on this ( such as a bit mask ) changing the behavior of the compiler can effectively be harmfull. I think that should be up to the people (ab)using the parser this way to correct their code by doing a explicit typecast.

There is no abuse of the parser. The parser has, since the very first moment that int64 and qword were supported in FPC, always parsed such numbers as int64. So people using it like that, are using it as designed. In fact, before Delphi supported uint64, it also parsed such values as int64.

Jonas

Ruediger Hahn
to Jonas Maebe: The reason is that $FFFFFFFFFFFFFFFF is parsed as an int64 by FPC. As a result it equals…
Jonas Maebe wrote 19 lines
On 25 Jun 2009, at 19:58, Ruediger Hahn wrote: > I am just wondering if this is a bug: Can anyone tell me why I get a > "range check error while evaluating constants" with the following > simple program: > > <code> > program Project1; > > const > MyVar : UInt64 = $FFFFFFFFFFFFFFFF; // 4 x 2 Bytes or 4 Words > > begin > end. > </code> The reason is that $FFFFFFFFFFFFFFFF is parsed as an int64 by FPC. As a result it equals -1, and -1 is not a valid uint64 value.

Ah yes, now I see. In Delphi it is quite the opposite: There I get a warning when I try to assign this value to an Int64: "Constant expression violates subrange bounds". Unfortunately it took me some hours to solve this problem because Lazarus by default has range checking enabled (-Cr), so I got an error instead of a warning.

Furthermore IMHO hex values _by_ _default_ should be interpreted as positive values. But that might be a matter of taste.

So what do I have to do then? It seems that a cast is the best solution: <code>

  MyConst : UInt64 = UInt64($FFFFFFFFFFFFFFFF);

</code>
Am I right?

Ruediger

Jonas Maebe
to Ruediger Hahn
Ruediger Hahn wrote 6 lines
So what do I have to do then? It seems that a cast is the best solution: <code> MyConst : UInt64 = UInt64($FFFFFFFFFFFFFFFF); </code> Am I right?

Yes, indeed. That will always work and is completely safe.

Jonas

Inoussa OUEDRAOGO
to Jonas Maebe: It's equally accurate. A hex number does not contain any sign information, so both…

2009/6/25 Jonas Maebe :

Show quoted text 19 lines
On 25 Jun 2009, at 20:33, Inoussa OUEDRAOGO wrote: > 2009/6/25 Jonas Maebe : >> >> On 25 Jun 2009, at 20:14, Inoussa OUEDRAOGO wrote: >> >>> as it makes one doubtfull about >>> the correctness of the program( In my case I debugged the program to >>> be sure that the "good" value was assigned). >> >> When it's changed, you will get the warning/error when assigning this >> value >> to an int64 and then those cases can be debugged. > > and that seems more accurate to me It's equally accurate. A hex number does not contain any sign information, so both interpretations are valid.

so it could be parsed as QWord accurately and assigned to a QWord (typed) variable without warning, as it is an assignment between two QWORD values.

Show quoted text 18 lines
>> to an int64 and then those cases can be debugged. It's the same when we >> changed from parsing $80000000-$FFFFFFFF as a longint to parsing it as a >> cardinal. Suddenly a whole bunch of code no longer worked correctly >> anymore >> then either, and we got a bunch of questions why code no longer compiled >> or >> produced warnings. > > IMHO warnings/errors should be reported as one is actually in a "out > of range" case. But if some code depends on this ( such as a bit mask > ) changing the behavior of the compiler can effectively be harmfull. > I think that should be up to the people (ab)using the parser this way > to correct their code by doing a explicit typecast. There is no abuse of the parser. The parser has, since the very first moment that int64 and qword were supported in FPC, always parsed such numbers as int64. So people using it like that, are using it as designed. In fact, before Delphi supported uint64, it also parsed such values as int64.

Just to clear out things :
* I am not for a blind compatibility with Delphi
* I am not a compiler dev guy, so I could be dead wrong
* I do want to understand the basics, the fondaments of such a decision ( to parsed as Int64 )

Inoussa O.
Jonas Maebe
to Inoussa OUEDRAOGO: 2009/6/25 Jonas Maebe : so it could be parsed as QWord accurately and assigned to a QWord…
Inoussa OUEDRAOGO wrote 9 lines
2009/6/25 Jonas Maebe : > > It's equally accurate. A hex number does not contain any sign > information, > so both interpretations are valid. so it could be parsed as QWord accurately and assigned to a QWord (typed) variable without warning, as it is an assignment between two QWORD values.

Pascal is a context-insensitive language, which means that the type of an expression does not depend on the context in which it is used. The types always fully depend on the expression itself. Therefore the parser cannot parse it as "int64 or qword", it has to pick one. So a choice has to be made between int64 and qword, and this choice has to be the same for every usage of such an expression. The choice has been, from the very beginning, int64.

Therefore, while the compiler could be changed to parse it as qword instead, it is not possible (without violating the spirit of the Pascal language and complicating the compiler) to make the compiler decide "this expression originally came from a hex value and it was possible to interpret it both as an int64 and a qword, and now I see it is used as a qword, so let us assume that the programmer meant it to represent a qword".

* I do want to understand the basics, the fondaments of such a decision ( to parsed as Int64 )

The original reasons were
a) FPC only supported int64 and no qword for a while, so when qword support was added the behaviour was kept the same for backward compatibility
b) Delphi compatibility

Jonas

Inoussa OUEDRAOGO
to Jonas Maebe

2009/6/25 Jonas Maebe :

Show quoted text 34 lines
On 25 Jun 2009, at 20:58, Inoussa OUEDRAOGO wrote: > 2009/6/25 Jonas Maebe : >> >> It's equally accurate. A hex number does not contain any sign >> information, >> so both interpretations are valid. > > so it could be parsed as QWord accurately and assigned to a QWord > (typed) variable without warning, as it is an assignment between two > QWORD values. Pascal is a context-insensitive language, which means that the type of an expression does not depend on the context in which it is used. The types always fully depend on the expression itself. Therefore the parser cannot parse it as "int64 or qword", it has to pick one. So a choice has to be made between int64 and qword, and this choice has to be the same for every usage of such an expression. The choice has been, from the very beginning, int64. Therefore, while the compiler could be changed to parse it as qword instead, it is not possible (without violating the spirit of the Pascal language and complicating the compiler) to make the compiler decide "this expression originally came from a hex value and it was possible to interpret it both as an int64 and a qword, and now I see it is used as a qword, so let us assume that the programmer meant it to represent a qword". >  * I do want to understand the basics, the fondaments of such a > decision ( to parsed as Int64 ) The original reasons were a) FPC only supported int64 and no qword for a while, so when qword support was added the behaviour was kept the same for backward compatibility b) Delphi compatibility

Good and clear explanation. Thank you very much.

Best regards.

Inoussa O.
m2
to Jonas Maebe: Pascal is a context-insensitive language, which means that the type of an expression does…
Jonas Maebe wrote 24 lines
On 25 Jun 2009, at 20:58, Inoussa OUEDRAOGO wrote: > 2009/6/25 Jonas Maebe : >> >> It's equally accurate. A hex number does not contain any sign >> information, >> so both interpretations are valid. > > so it could be parsed as QWord accurately and assigned to a QWord > (typed) variable without warning, as it is an assignment between two > QWORD values. Pascal is a context-insensitive language, which means that the type of an expression does not depend on the context in which it is used. The types always fully depend on the expression itself. Therefore the parser cannot parse it as "int64 or qword", it has to pick one. So a choice has to be made between int64 and qword, and this choice has to be the same for every usage of such an expression. The choice has been, from the very beginning, int64. Therefore, while the compiler could be changed to parse it as qword instead, it is not possible (without violating the spirit of the Pascal language

The fact that Borland regarded "$FF..FF" as a 2's complement representation and not as a base-16 representation of an integer is not really what I would call "Pascal spirit". As a matter of fact, "Borland mess" would be more appropriate. :-)

mm
----
http://www.ellipsa.eu/

Marco van de Voort
to m2

In our previous episode, m2 said:

Show quoted text 7 lines
> instead, it is not possible (without violating the spirit of the Pascal > language The fact that Borland regarded "$FF..FF" as a 2's complement representation and not as a base-16 representation of an integer is not really what I would call "Pascal spirit". As a matter of fact, "Borland mess" would be more appropriate. :-)

Hmm, I'd say it is Pascal spirit to have a signed base type.

Jürgen Hestermann
to m2: The fact that Borland regarded "$FF..FF" as a 2's complement representation and not as a…
The fact that Borland regarded "$FF..FF" as a 2's complement representation and not as a base-16 representation of an integer is not really what I would call "Pascal spirit". As a matter of fact, "Borland mess" would be more appropriate. :-)
I always avoid such imponderabilities by using fillchar to set all bits
of a structure to 1 (or 0);
fillchar(X,$F);

And single bits can be modified with AND/OR afterwards if needed.