Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Zugriffsverletzung nach Modulus (https://www.delphipraxis.net/150562-zugriffsverletzung-nach-modulus.html)

RebellX 20. Apr 2010 23:00


Zugriffsverletzung nach Modulus
 
Hi,

sitze schon seit einer Weile an folgendem Problem:

In einem Spiel soll ein Spieler durch Karten bewegt werden. Dazu habe ich eine Funktion zur Auswertung der Karten geschrieben. Doch nach einer Konstanten Zahl an Testläufen kommt es immer zu folgendem Problem:

Zitat:

... Problem mit folgender Meldung auf: 'Zugriffsverletzung bei 0x0040c5ad: Schreiben von Adresse 0x00030fc0'. Prozess angehalten...
Die Meldung erscheint zusammen mit dem CPU-Fenster, dort wird immer eins von beiden angezeigt:

Zitat:

push ebx
push $00000400
Danach war eine weitere Ausführung des Programms nicht mehr möglich... :(

Ich hab soweit Code auskommentiert und konnte herausfinden, das ohne folgende Zeilen das Problem nicht mehr auftritt:

Delphi-Quellcode:
player.angle := (player.angle - 1 + 4) mod 4;
Delphi-Quellcode:
player.angle := (player.angle + 1 + 4) mod 4;
Delphi-Quellcode:
player.angle := (player.angle + 2 + 4) mod 4;
player.angle sollte immer in dem Bereich zwischen 0 und 3 gehalten werden und wird auch nur so geändert. Außerdem sollte das keine Zugriffsverletzung auslösen... :?

Weiß jemand, woher soetwas stammen könnte?

Schonmal Danke im Vorraus

RebellX


P.S.: Ich benutze statische und dynamische Arrays, doch auch wenn ich auf die nicht mehr zugreife tritt das Problem auf.

P.P.S.: Ich benutze Delphi 7

BUG 20. Apr 2010 23:14

Re: Zugriffsverletzung nach Modulus
 
Mal ne doofe Idee: kann es sein das du Player irgendwo freigegeben hast (ist das ein Objekt oder ein Record?) :glaskugel:

Ich glaube um ein bisschen mehr Code-Preisgabe wirst du hierbei nicht herumkommen.

RebellX 20. Apr 2010 23:47

Re: Zugriffsverletzung nach Modulus
 
Zitat:

Mal ne doofe Idee: kann es sein das du Player irgendwo freigegeben hast (ist das ein Objekt oder ein Record?) Was sagt die Glaskugel?
Kann eigentlich nicht sein, da
A: player ist in der procedure mit var übergeben worden, sonst aber ein array [1..8] of tplayer (record)
B: Ich davor und danach darauf zugreifen kann, wenn ich die o.g. Zeilen auskommentiere
C: Ich recht wenig freigebe, da das meiste statisch ist und ich mich so nicht drum kümmern muss

Das ganze Projekt ist eine Art Brettspiel. Bis zu 8 Spieler können durch 5 Aktionen pro Zug über ein Spielfeld sich bewegen und müssen Punkte erreichen. Dabei werden sie zusätzlich von den verschiedenen Feldern des Spielfeldes bewegt.
Heißt also in der Berechnung hat jeder Spieler eine X und Y Koordinate sowie eine Orientierung (halt die Eigenschaft angle, also 0, 90, 180, 270° als 0-3 dargestellt).
Zur Anzeige der Bewegung wird dafür wieder rückwärts eine "Animation" erstellt, sprich es wird gespeichert, wie der Spieler bewegt wurde und er wird fürs Anzeigen zurückbewegt. Diese "Animation" wird dann immer weiter verringert, bis der Spieler da angezeigt wird, wo er tatsächlich steht. Das funktionioniert auch ohne die drei Zeilen ohne Probs. Nur sind die unumgänglich um die Spieler zu drehen (oder wie könnte man das einfacher machen?)

Ein paar Definitionen von TPlayer etc. :

Delphi-Quellcode:
type
  TPlayer = record
    X, Y, angle: byte;
    //Animation
    ani_x, ani_y, ani_z, ani_angle, ani_wait: array of smallint;
    ani_count: byte;
    //... unwichtige booleanwerte für Handkarten etc, noch nicht implementiert...
  end;

const
  Move_1     = $01;
  Move_2     = $02;
  Move_3     = $03;
  Turn_Left = $04;
  Turn_Right = $05;
  U_Turn    = $06;
  Back_Up   = $07;
Die Methode mit der Berechnung:

Delphi-Quellcode:
procedure execute(befehl: byte; var Aplayer: tplayer);
var i: byte;
begin
  if (befehl = 0) or (befehl > 7) then exit;
  if befehl <= move_3 then
    for i := 1 to befehl do
    begin
      moveplayer(aplayer, aplayer.angle);
    end
  else
  if befehl = Turn_left then
  begin
    aplayer.angle := (aplayer.angle - 1 + 4) mod 4;
    addanimate(aplayer, AT_Angle, +30);
  end
  else
  if befehl = Turn_Right then
  begin
    aplayer.angle := (aplayer.angle + 1 + 4) mod 4;
    addanimate(aplayer, AT_Angle, -30);
  end
  else
  if befehl = U_Turn then
  begin
    aplayer.angle := (aplayer.angle + 2 + 4) mod 4;
    if random(2) = 1 then addanimate(aplayer, AT_Angle, -60)
    else
    addanimate(aplayer, AT_Angle, +60);
  end
  else
  if befehl = Back_Up then
  begin
    moveplayer(aplayer, (aplayer.angle + 2 + 4) mod 4);
  end;
end;
Moveplayer und addanimate arbeiten ohne Probleme und auch das Auskommentiere schafft keine Besserung.

P.S.: Player heißt da Aplayer, da Player im Hauptprogramm eben ein Array ist

Billa 21. Apr 2010 07:51

Re: Zugriffsverletzung nach Modulus
 
Benutze einfach mal eine Hilfsvariable und teile

Delphi-Quellcode:
player.angle := (player.angle - 1 + 4) mod 4;
in mehrere Anweisungen auf. Auf die Art sieht man z.B. Bereichsunter- oder überschreitungen (etwa durch die Reihenfolge, in der die Summierung ausgewertet wird) viel eher. Player.Angle ist ja BYTE ... also besser erst +4 und dann -1.... nur so eine (ungetestete) Idee ...

sirius 21. Apr 2010 07:58

Re: Zugriffsverletzung nach Modulus
 
Der Teil aus dem CPU-Fenster passt absolut nicht mit deiner Code-Zeile zusammen.

Kannst du mal in den Optionen die Bereichüberprüfung anschalten.

RebellX 21. Apr 2010 08:29

Re: Zugriffsverletzung nach Modulus
 
Bereichsprüfung ist eigentlich schon angeschaltet gewesen, sofern ich mich nicht irre.

zumindest habe ich in jeder Unit {+R} gesetzt gehabt, wobei player.angle nur in case Structuren verglichen wird...

Ob es -1+4 ist oder +1+4 macht keinen Unterschied, auch wenn ich -1+4 rausnehme tritt der Fehler auf.

himitsu 21. Apr 2010 08:57

Re: Zugriffsverletzung nach Modulus
 
Eine Rechenoperation kann keine Zugriffsverletzung auslösen, also ist es egal ob +1, -1 oder sonstwas.

Es kann höchstens eine Zugriffsverletzung beim Zugriff auf Player erfolgen.
Code:
player.angle := player.angle;
       ^               ^
       ^               Zugriffverletzung "Lesen von Adresse"
       Zugriffverletzung "[b]Schreiben von Adresse[/b]"
Wenn aber Player "ungültig" ist, dann gäbe es mit hoher Wahrscheinlichkeit schon beim Lesen einen Fehler und nicht erst bei Schreiben, zumindestens im angegebenen Speicherbereich von $00000000 bis $0000FFFF ( $00030fc0 ).

Luckie 21. Apr 2010 09:08

Re: Zugriffsverletzung nach Modulus
 
TPlayer ist aber, laut seiner Aussage, ein Record.

himitsu 21. Apr 2010 09:16

Re: Zugriffsverletzung nach Modulus
 
Zitat:

Zitat von Luckie
TPlayer ist aber, laut seiner Aussage, ein Record.

OK, dann kann der Fehler also nicht direkt in dieser Codezeile liegen,
es sei denn dieses Player ist ein Var/Const-Parameter einer Prozedur und der übergebene Parameter-Wert ist "ungültig".

Aber wenn sonst alles "korrekt" ist, dann kann der Fehler also nicht in dieser Codezeile stecken.

Da er ja angeblich auch Arrays verwendest:
Hast du denn schonmal die Bereichprüfung aktivert? (z.B. in den Projektoptionen)

RebellX 21. Apr 2010 18:00

Re: Zugriffsverletzung nach Modulus
 
So, hab nochmal sichergestellt, das die Bereichsprüfung an ist (ich kann Integeroverflow etc. erzeugen und krieg nen Fehler).

Hab auch versucht, auf das Modulus zu verzichten und die Animationen (hat zwar dynamische Arrays, hatte aber funktioniert) noch mal rausgenommen.

Die Stelle mit ehemals - 1 + 4 sähe nun so aus:

Delphi-Quellcode:
    while aplayer.angle > 3 do aplayer.angle := aplayer.angle - 4;
    aplayer.angle := aplayer.angle + 3;
    while aplayer.angle > 3 do aplayer.angle := aplayer.angle - 4;
wenn ich davon die 2. Zeile auskommentiere, funzt es ohne Probleme. Wenn ich aber +3 rechne (muss als byte ja gehen, die 1. und 3. Anweisungen stellen sicher, das man im Rahmen von 0..3 bleibt), sagt er wieder Zugriffsverletzung und zeigt im CPU-Fenster auf push $00000400 oder push ebx. Die anderern beiden Fälle hab ich dabei mal auskommentieren können.

Habe noch
Delphi-Quellcode:
  if not assigned(@aplayer) then exit;
am Anfang eingefügt, bringt auch keine Besserung...

Und eine Int64 Variable zum Feststellen, ob es mein Speicher ist, auf den ich zugreife hat auch nichts gebracht:

Delphi-Quellcode:
  if not aplayer.Testint = test then exit;
Testint und test sind Int64, test eine sehr große Konstante.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:34 Uhr.
Seite 1 von 2  1 2      

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