0

This question may sound silly but I can not understand the idea behind the not operator on constant integers. I get the following results:

  • not $FF => $FF00
  • not $FFFF => $FFFF0000
  • not $FFFFFFFF => $00
  • not $FFFFFFFFFFFFFFFF => $00

The first two values look wrong to me.

The documentation states:

For example, not performs bitwise negation on an integer operand

and later:

The result of a not operation is of the same type as the operand

This is not in line with the observed behaviour.

Full code example:

unit Unit5;

interface

procedure c();

implementation

uses Vcl.Dialogs, System.SysUtils;

procedure Invert(v: ShortInt); overload; begin
  ShowMessage('ShortInt $' + v.ToHexString());
end;

procedure Invert(v: SmallInt); overload; begin
  ShowMessage('SmallInt $' + v.ToHexString());
end;

procedure Invert(v: Integer); overload;
begin
  ShowMessage('Integer $' + v.ToHexString());
end;

procedure c();
const
  byteValue = not $FF; // = $FF00
  wordValue = not $FFFF; // = $FFFF0000
  cardValue = not $FFFFFFFF; // = $00
  uint64Value = not $FFFFFFFFFFFFFFFF; // = $00
begin
  Invert(byteValue);
  Invert(wordValue);
  Invert(cardValue);
  Invert(uint64Value);
end;

end.
ventiseis
  • 3,029
  • 11
  • 32
  • 49
  • This question is essentially the same as this one: https://stackoverflow.com/questions/32160057/what-is-the-type-of-a-integral-true-constant – David Heffernan Apr 25 '18 at 23:35

1 Answers1

4

The compiler is free* to pick a suitable type for true constants, if there can be an ambiguity.

You need to help out in this case by using a value typecast:

const
   byteValue = Byte(not $FF);  // => $00  (ShortInt)
   wordValue = Word(not $FFFF); // => $00 (ShortInt) 

To avoid overloaded confusion, since you only offer signed printout alternatives:

const
   byteValue = ShortInt(not $FF);  // => $00 (ShortInt)
   wordValue = SmallInt(not $FFFF); // => $0000 (SmallInt) 

When no direct overloaded procedure matches an ordinal type, it can be difficult to predict which overload the compiler selects.


From Declared_Constants#True_Constants:

The syntax for declaring a true constant is:

const identifier = constantExpression

where identifier is any valid identifier and constantExpression is an expression that the compiler can evaluate without executing your program.

If constantExpression returns an ordinal value, you can specify the type of the declared constant using a value typecast.



Added a full test:

program Project110;

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

procedure Invert(v: ShortInt); overload; begin
  WriteLn('ShortInt $' + v.ToHexString());
end;

procedure Invert(v: SmallInt); overload; begin
  WriteLn('SmallInt $' + v.ToHexString());
end;

procedure Invert(v: Integer); overload;
begin
  WriteLn('Integer $' + v.ToHexString());
end;

procedure Invert(v: Int64); overload;
begin
  WriteLn('Int64 $' + v.ToHexString());
end;
    
procedure c();
const
  byteValue = ShortInt(not $FF); // = ShortInt $00
  wordValue = SmallInt(not $FFFF); // = SmallInt $0000
  cardValue = Integer(not $FFFFFFFF); // = Integer $00000000
  uint64Value = Int64(not $FFFFFFFFFFFFFFFF); // = Int64 $0000000000000000
begin
  Invert(byteValue);
  Invert(wordValue);
  Invert(cardValue);
  Invert(uint64Value);
end;

begin
  c;
  ReadLn;
end.
Community
  • 1
  • 1
LU RD
  • 34,438
  • 5
  • 88
  • 296
  • @RemyLebeau I'm afraid your edit is wrong. The compiler picks the `ShortInt` overload in this case. – LU RD Apr 25 '18 at 22:32
  • I added a value typecast that matches your overloaded functions types alternatives as well. It is not always easy to know which overload the compiler will select. – LU RD Apr 25 '18 at 22:40
  • To quote @DavidHeffernan: *"In fact the documentation of the overloading rules is incomplete and the only way to fully understand the compiler's behaviour is by reverse engineering."* – LU RD Apr 25 '18 at 22:57
  • 1
    this question is highly relevant: https://stackoverflow.com/questions/32160057/what-is-the-type-of-a-integral-true-constant – David Heffernan Apr 25 '18 at 23:38
  • Thank you for this thorough answer. Unfortunately, there is no _detailed_ ObjectPascal specification to look up such things... – ventiseis Apr 26 '18 at 12:23
  • In this case the documentation is wrong as well, but David sorted out the correct compiler type inference logic for type constants in his linked answer. – LU RD Apr 26 '18 at 13:00