Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   EDivByZero ohne Sysutils fangen (https://www.delphipraxis.net/162070-edivbyzero-ohne-sysutils-fangen.html)

Win32.API 4. Aug 2011 14:14

Delphi-Version: XE

EDivByZero ohne Sysutils fangen
 
Hallo Zusammen!

Ich stehe gerade etwas auf dem Schlauch. Wieso fängt Delphi diese Exception nicht:

Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}
{$O-}

//uses SysUtils; //Ohne Kommentar funktioniert es wunderbar :O

var
  d: Integer;
begin
  try
    d := 0;
    d := d div d;
  except
    writeln('Wer haette es gedacht ...');
  end;
  readln;
end.
Na gut, das es ohne die Sysutils keine EDivByZero Exception gibt ist irgendwie klar, aber ich hätte trotzdem erwartete, dass ich im Except-Zweig lande.

Gibt es eine Möglichkeit, Delphi davon zu Überzeugen, die Exception auch ohne Sysutils im Except-Block zu fangen? SEH per Hand (fs[0] ...), SetUnhandledExceptionFilter oder AddVectoredExceptionHandler würde ich gerne vermeiden.

Schönen Gruß,
Win32.API

Nersgatt 4. Aug 2011 14:19

AW: EDivByZero ohne Sysutils fangen
 
Bei dem Code wird die Division wegoptimiert.

Win32.API 4. Aug 2011 14:26

AW: EDivByZero ohne Sysutils fangen
 
Im Release-Modus mit
Delphi-Quellcode:
{$O+}
schon, ich meine aber eigentlich den Debug-Modus mit
Delphi-Quellcode:
{$O-}
.

Neutral General 4. Aug 2011 14:30

AW: EDivByZero ohne Sysutils fangen
 
Hast du mal Breakpoints gesetzt?

So kannst du ja ganz leicht feststellen ob und was da wegoptimiert wurde oder auch nicht.
Mach halt im Zweifelsfall mal ein writeln(d); hinter die Division.

DeddyH 4. Aug 2011 14:33

AW: EDivByZero ohne Sysutils fangen
 
Du meinst writeln(d); ;)

Neutral General 4. Aug 2011 14:37

AW: EDivByZero ohne Sysutils fangen
 
Öhm.. ja, richtig! :oops:

Win32.API 4. Aug 2011 14:41

AW: EDivByZero ohne Sysutils fangen
 
Mit
Delphi-Quellcode:
{$O-}
wird nichts "wegoptimiert". Darum geht es hier aber auch nicht, es geht auch nicht darum, ob der Quelltext so Sinn macht oder nicht. Die Frage ist wieso verweigert der Exception-Handler den Dienst, wenn ich die Sysutils nicht einbinde.


Edit: Das Problem ist, dass die Exception geworfen wird, aber der Exception-Handler diese nicht fängt. Das Programm stürzt also ohne Sysutils ab (Projekt 1 funktioniert nicht mehr ...).

himitsu 4. Aug 2011 14:51

AW: EDivByZero ohne Sysutils fangen
 
Vermutlich weil die SysUtils nicht nur die Exceptionklassen bereitstellt, sondern auch noch so Einiges für die Exception-Behandlung initialisieren/einbinden.

Ohne SysUtils wird bei dieser Exception ein
Zitat:

Halt
ausgeführt und ein entprechender Fehlercode zurückgegeben (ans System).
Die Behandlung bricht also sofort ab und das war's dann, da die Exception unbehandelt bis in System durchgerauscht ist.

gammatester 4. Aug 2011 14:52

AW: EDivByZero ohne Sysutils fangen
 
Zitat:

Zitat von Win32.API (Beitrag 1115084)
Mit
Delphi-Quellcode:
{$O-}
Die Frage ist wieso verweigert der Exception-Handler den Dienst, wenn ich die Sysutils nicht einbinde.

Macht er doch gar nicht, er schreibt doch
Zitat:

Runtime error 200 at 00402482
Es ist halt nicht der aus Sysutils, sondern der, der default da ist (wenn Du VCL benutzt hast Du immer Sysutils).

himitsu 4. Aug 2011 14:56

AW: EDivByZero ohne Sysutils fangen
 
Delphi-Quellcode:
procedure RunErrorAt(ErrCode: Integer; ErrorAtAddr: Pointer);
begin
  ErrorAddr := ErrorAtAddr;
  _Halt(ErrCode);
end;
Ohne SysUtils ladet man dort und mit SysUtils wird stattdessen für bekannte Fehler die entsprechende Exception ausgelöst.

Win32.API 4. Aug 2011 15:03

AW: EDivByZero ohne Sysutils fangen
 
Zitat:

Zitat von gammatester (Beitrag 1115086)
Zitat:

Zitat von Win32.API (Beitrag 1115084)
Mit
Delphi-Quellcode:
{$O-}
Die Frage ist wieso verweigert der Exception-Handler den Dienst, wenn ich die Sysutils nicht einbinde.

Macht er doch gar nicht, er schreibt doch
Zitat:

Runtime error 200 at 00402482
Es ist halt nicht der aus Sysutils, sondern der, der default da ist (wenn Du VCL benutzt hast Du immer Sysutils).

Der Delphi interne Exception-Handler verschluckt die Exception und reicht sie nicht wie erwartet an meinen lokalen Handler weiter. Was ich sehr merkwürdig finde.

Zitat:

Zitat von himitsu (Beitrag 1115087)
Delphi-Quellcode:
procedure RunErrorAt(ErrCode: Integer; ErrorAtAddr: Pointer);
begin
  ErrorAddr := ErrorAtAddr;
  _Halt(ErrCode);
end;
Ohne SysUtils ladet man dort und mit SysUtils wird stattdessen für bekannte Fehler die entsprechende Exception ausgelöst.

DivByZero ist doch schon eine Exception wieso wird diese nicht weitergereicht? Im Klartext heißt das, dass ich keine Chance habe über einen lokalen Delphi-Exception-Handler diese Exception zu fangen? :roll:

Bernhard Geyer 4. Aug 2011 15:16

AW: EDivByZero ohne Sysutils fangen
 
Zitat:

Zitat von Win32.API (Beitrag 1115091)
DivByZero ist doch schon eine Exception wieso wird diese nicht weitergereicht? Im Klartext heißt das, dass ich keine Chance habe über einen lokalen Delphi-Exception-Handler diese Exception zu fangen? :roll:

Hast du der FPU/CPU auch gesagt das für dich DivByZero eine Exception ist?
Stichwort wäre hier: SetExceptionMask

Win32.API 4. Aug 2011 15:34

AW: EDivByZero ohne Sysutils fangen
 
IMHO initialisiert Delphi die FPU mit Exceptions. SetExceptionMask liegt leider in der Math.pas die Sysutils.pas importiert. Ein direktes Aufrufen von
Delphi-Quellcode:
Set8087CW($1372)
bringt aber leider auch keine Besserung.

gammatester 4. Aug 2011 15:35

AW: EDivByZero ohne Sysutils fangen
 
Zitat:

Zitat von Win32.API (Beitrag 1115091)
Im Klartext heißt das, dass ich keine Chance habe über einen lokalen Delphi-Exception-Handler diese Exception zu fangen? :roll:

Tip mal ExceptProc und drück F1, falls Du kein Delphi mit Onlinehilfe mehr hast, hier die Ausgabe von D6:

Zitat:

Zitat von Delphi Hilfe

Points to the lowest-level RTL exception handler.

Unit System

Category exception handling routines

var ExceptProc: Pointer;

Description

ExceptProc handles unhandled exceptions (exceptions that have not been caught in the except portion of a try..except statement.) If your application has a TApplication object, it automatically catches exceptions and generates an OnException event (to which you can respond using either the application’s or a TApplicationEvents object’s OnException event handler). Thus, because the TApplication object catches the exceptions, they never reach the ExceptProc handler. However, even if you have a TApplication object, it does not catch exceptions generated during initialization and finalization. These are handled by ExceptProc.

You can hook into ExceptProc to change how unhandled exceptions are reported. To do so, save the contexts of ExceptProc before changing it to the address of your own exception handler. The first statement of your new exception handler must then reinstall the saved value of ExceptProc. In this way, the ExceptProc procedure becomes part of a chain of exception procedures, each of which is executed in reverse order of installation.

The procedure assigned to ExceptProc must have a signature such as the following:

procedure ExceptHandler(ExceptObject: TObject; ExceptAddr: Pointer);


Win32.API 4. Aug 2011 15:45

AW: EDivByZero ohne Sysutils fangen
 
Dieser Handler bekommt von der Exception leider auch nichts mit, außerdem ist er global, was ich nach wie vor gerne vermeiden würde.

himitsu 4. Aug 2011 15:56

AW: EDivByZero ohne Sysutils fangen
 
Zitat:

Zitat von Win32.API (Beitrag 1115091)
DivByZero ist doch schon eine Exception wieso wird diese nicht weitergereicht? Im Klartext heißt das, dass ich keine Chance habe über einen lokalen Delphi-Exception-Handler diese Exception zu fangen? :roll:

Eben nicht.
Es ist eine System-Exception und keine Delphi-Exception.
Ohne SysUtils keine Delphi-Exceptions und ohne Delphi-Exceptions (also die Objekte, welche ein Nachfahre von der Klasse Exception sind), gibt es auch keine Try-Except/Finally-Behandlung.

Die System-Exception für
Delphi-Quellcode:
div 0
hat den Fehlercode 200, welches nach TRuntimeError reDivByZero gemapt wird.
Mit eingebundener SysUtils wird dann reDivByZero abgefangen und stattdessen eine Exception EDivByZero ausgelöst.

Delphi-Quellcode:
{ RTL error handler }

procedure ErrorHandler(ErrorCode: Byte; ErrorAddr: Pointer); export;
var
  E: Exception;
begin
  case ErrorCode of
    Ord(reOutOfMemory):
      E := OutOfMemory;
    Ord(reInvalidPtr):
      E := InvalidPointer;
    Ord(reDivByZero)..Ord(High(TRuntimeError)):
      begin
        with ExceptMap[ErrorCode] do
          E := ExceptTypes[EClass].Create(EIdent);
      end;
  else
    E := CreateInOutError;
  end;
  raise E at ErrorAddr;
end;

const
  ExceptTypes: array[TExceptType] of ExceptClass = (
    EDivByZero,
    ERangeError,
    ...);

  ExceptMap: array[Ord(reDivByZero)..Ord(High(TRuntimeError))] of TExceptRec = (
    (EClass: etDivByZero; EIdent: SDivByZero),
    (EClass: etRangeError; EIdent: SRangeError),
    ...);


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:16 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz