Delphic flag overflow

If i do it

var a,b,c:cardinal; begin a:=$80000000; b:=$80000000; c:=a+b; end; 

c will be 0, because the add is full. What is the best way to catch this crowded boolean? (a+b<a) or (a+b<b) ? a really nice way would be with inline assembler, but I'm not so fruitful in assembler (although I assumed it would include something like JO )

+7
source share
5 answers

In assembly, the term Overflow usually refers to signed arithmetic and means that the sign of the sum is different from the signs of both operands; for unsigned arithmetic, it is preferable to use the term Carry .

You can implement the add-on with checking for overflow (transfer) in a pure pascal:

 // signed add - returns True if no overflow produced function SAdd(A, B: integer; out C: integer): Boolean; begin C:= A + B; Result:= (A xor B < 0) // operands have different signs or (C xor A >= 0); // sum has the same sign as operands end; // unsigned add - returns True if no carry produced function UAdd(A, B: Cardinal; out C: Cardinal): Boolean; begin C:= A + B; Result:= (C >= A); end; 

The same functions in the assembly are an optimized version of Andreas's solution:

 // Signed Add function SAdd(A, B: Integer; out C: Integer): Boolean; asm ADD EAX,EDX MOV [ECX],EAX SETNO AL end; // Unsigned Add function UAdd(A, B: Cardinal; out C: Cardinal): Boolean; asm ADD EAX,EDX MOV [ECX],EAX SETNC AL end; 
+8
source

I'm not a build specialist either, but I think this works:

Signed Version:

 function TryAdd(a, b: integer; out c: integer): boolean; asm ADD EAX, EDX // EAX := a + b; MOV [c], EAX // c := EAX; JO @@END // if overflow goto end; MOV EAX, true // result := true RET // Exit; @@END: XOR EAX, EAX // result := false; end; procedure TForm1.Button1Click(Sender: TObject); var c: integer; begin if TryAdd(MaxInt - 5, 6, c) then ShowMessage(IntToHex(c, 8)) else ShowMessage('Overflowed!'); end; 

Unsigned version:

 function TryAdd(a, b: cardinal; out c: cardinal): boolean; asm ADD EAX, EDX // EAX := a + b; MOV [c], EAX // c := EAX; JC @@END // if overflow goto end; MOV EAX, true // result := true RET // Exit; @@END: XOR EAX, EAX // result := false; end; procedure TForm1.Button1Click(Sender: TObject); var c: cardinal; begin if TryAdd($A0000000, $C0000000, c) then ShowMessage(IntToHex(c, 8)) else ShowMessage('Overflowed!'); end; 
+5
source

Andreas solution in pure pascal (with a fixed TryAdd, as suggested in the comments).

 function TryAdd(a, b: integer; out c: integer): boolean; overload; var sum: int64; begin sum := int64(a) + int64(b); Result := (Low(integer) <= sum) and (sum <= High(integer)); c := integer(Int64Rec(sum).Lo); end; function TryAdd(a, b: cardinal; out c: cardinal): boolean; overload; var sum: int64; begin sum := int64(a) + int64(b); Result := sum <= High(cardinal); c := Int64Rec(sum).Lo; end; procedure TForm32.Button1Click(Sender: TObject); var c: integer; begin if TryAdd(MaxInt - 5, 6, c) then ShowMessage(IntToHex(c, 8)) else ShowMessage('Overflowed!'); end; 
+4
source
 {$OPTIMIZATION OFF} procedure TForm1.FormCreate(Sender: TObject); function Overflow(): WordBool; const fOverflow = $0800; asm PUSHF POP AX AND AX, fOverflow; end; var I, J, K: Integer; begin I := $80000000; J := $80000000; { method A - read FLAGS register } {$OVERFLOWCHECKS OFF} K := I + J; if Overflow() then Windows.Beep(5000, 50); { method B - have compiler to generate check and catch an exception } {$OVERFLOWCHECKS ON} try K := I + J; except on E: EIntOverflow do ShowMessage('OH SHI-'); end; end; 

Naturally, reading FLAGS using method A should immediately follow the statement, so it makes this method not very practical. In contrast, Method B uses high-level structured error handling and is therefore recommended.

0
source

I hate assembler (completely non-portable), so I use overflow checking, for example:

 {$IFOPT Q-} {$DEFINE CSI_OVERFLOWCHECKS_OFF} {$ENDIF} {$OVERFLOWCHECKS ON} a:=$80000000; b:=$80000000; c:=a+b; {$IFDEF CSI_OVERFLOWCHECKS_OFF} {$UNDEF CSI_OVERFLOWCHECKS_OFF} {$OVERFLOWCHECKS OFF} {$ENDIF} 
0
source

All Articles