Vorsicht mit Arrayindices

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Vorsicht mit Arrayindices

Beitrag von Mathias »

Und warum zum Henker sollte ich range checks ausschalten?

Aus Geschwindigkeitsgründen, jede Überprüfung kostet Zeit.

Was bis jetzt geschrieben wurde, ist noch alles harmlos, man kann auch Array negativ deklarieren.

Code: Alles auswählen

var
  a0: array[-10.. -5] of byte;
  a1: array[-10..5] of byte;


Wen man bei 0 beginnt hat man den Vorteil, der Zugriff ist immer gleich, egal ob die Array dynamisch oder statisch ist.
Wen man eine Array lokal in einer Procedure verwendet, dann ist es nicht so tragisch, wen sie nicht bei 0 beginnt, aber bei systemweiten Sachen ist es aber von Vorteil mit 0 zu beginnen.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Vorsicht mit Arrayindices

Beitrag von m.fuchs »

Mathias hat geschrieben:
Und warum zum Henker sollte ich range checks ausschalten?

Aus Geschwindigkeitsgründen, jede Überprüfung kostet Zeit.

Ich wiederhole mich solange bis es angekommen ist: Unittests, Unittests, Unittests! Und zwar mit allen Checks.
Da kommt es dann auf die Zeitverzögerungen der Prüfungen nicht an und sorgt für einen funktionierenden Code.

All diese Probleme die hier geschildert werden, habe nichts mit dem nicht-0-basiertem Index zu tun. Dass ich irgendwo hinschreibe, wo ich nicht hinschreiben soll kann mir auch so passieren. Und eben darum sichert man das ab.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Vorsicht mit Arrayindices

Beitrag von Warf »

m.fuchs hat geschrieben:Ich wiederhole mich solange bis es angekommen ist: Unittests, Unittests, Unittests! Und zwar mit allen Checks.
Da kommt es dann auf die Zeitverzögerungen der Prüfungen nicht an und sorgt für einen funktionierenden Code.

All diese Probleme die hier geschildert werden, habe nichts mit dem nicht-0-basiertem Index zu tun. Dass ich irgendwo hinschreibe, wo ich nicht hinschreiben soll kann mir auch so passieren. Und eben darum sichert man das ab.


Dagegen sage ich ja nichts, aber du hast meine prämisse falsch verstanden. Man muss davon ausgehen das bei einem größeren Projekt irgendwann es zwangsläufig passiert das jemand mit for i:=0 to Length(arr)-1 durch einen array iteriert. Das viele eventuell drüber iterieren weil sie das -1 weglassen gibt es zwar auch, aber danach lässt sich sehr einfach finden. Dafür muss man den Code nicht verstanden haben, jedem Programmierer egal ob java, Pascal oder C würde bei der zeile for i:=0 to Length(arr) do die arlamglocken läuten, während for i:=0 to Length(arr)-1 auf den ersten blick korrekt aussieht und man muss überall die datentypen überprüfen was deutlich mehr aufwand ist. Und Testsuites sind niemals vollständig, selbst die seit jahrzehnten gepflegte CoreUtils Test suite coverd nur 80% des Codes. Das muss nur eine kleine For schleife sein die von den Tests nicht abgedeckt wird und irgendwann knallt es

Wenn man alle Arrays mit 0 beginnen lässt schließt man eine komplette semantische Fehlerklasse aus. Man könnte meinetwegen auch alle arrays mit 1 oder -45 anfangen lassen, dann ist es aber nicht mit den Dynamischen Arrays konsistent

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Vorsicht mit Arrayindices

Beitrag von m.fuchs »

Warf hat geschrieben:Man muss davon ausgehen das bei einem größeren Projekt irgendwann es zwangsläufig passiert das jemand mit for i:=0 to Length(arr)-1 durch einen array iteriert.


Warum muss man davon ausgehen? Den Code für die Iterieration schreibt der Entwickler der das Array angelegt hat. Wenn jemand den Code für die Iteration ändert, dann macht er das ja nur weil er auch die Arraygrenzen ändert. Oder umgekehrt.

Sinnvoller als die Forderung nur Arrays mit Startindex 0 zu verwenden wäre es doch die ausschließlich Verwendung von Low und High zu fordern. Das beseitigt alle Probleme.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: Vorsicht mit Arrayindices

Beitrag von kupferstecher »

siro hat geschrieben:Ich hab in meinem ganzen Leben noch kein Array gehabt, was nicht bei 0 angefangen hat.

Eigentlich braucht man fast nie ein bei null beginnendes Array, das -1 zeigt ja auch, dass der Nullindex unnatürlich ist. In C ist das anders, dort muss (musste?) man ja Arrays selbst verwalten. Da dynamische Arrays aber in FreePascal immer bei null anfangen, verwende ich das auch bei statischen Arrays meistens.

Warf hat geschrieben:während for i:=0 to Length(arr)-1 auf den ersten blick korrekt aussieht und [...]

Der Fehler kann ja auch innerhalb der Schleife liegen. Beispiel:

Code: Alles auswählen

for ii:= 0 to length(arr)-1 
 do arr[ii]:= arr[ii]+ arr[ii+1]

Das passiert besonders leicht, wenn man versucht eine Schleife auf null zu 'biegen', die natürlicherweise andere Grenzen hätte.

Es gibt übrigens einen Wikiartikel zu diesem Thema (in Englisch):
http://wiki.freepascal.org/Defensive_pr ... techniques

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Vorsicht mit Arrayindices

Beitrag von Socke »

kupferstecher hat geschrieben:Es gibt übrigens einen Wikiartikel zu diesem Thema (in Englisch):
http://wiki.freepascal.org/Defensive_pr ... techniques

Dass man mit einem Set über einen Range-Index iterieren kann, wusste ich noch nicht. Interessantes Feature!
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Vorsicht mit Arrayindices

Beitrag von Mathias »

Dass man mit einem Set über einen Range-Index iterieren kann, wusste ich noch nicht. Interessantes Feature!

Dann gucke mal die Deklaration von TColor, TGraphicsColor an.

Code: Alles auswählen

  TGraphicsColor = -$7FFFFFFF-1..$7FFFFFFF;

Selbst habe ich sowas noch nie gebraucht.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Vorsicht mit Arrayindices

Beitrag von marcov »

Code: Alles auswählen

 
 for i:=low(fsomearray) to high(fsomearray) do
 ...


oder

Code: Alles auswählen

 
var x : integer; // element typ.
 for x in fsomearray do
 ...

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Vorsicht mit Arrayindices

Beitrag von Warf »

kupferstecher hat geschrieben:
siro hat geschrieben:Ich hab in meinem ganzen Leben noch kein Array gehabt, was nicht bei 0 angefangen hat.

Eigentlich braucht man fast nie ein bei null beginnendes Array, das -1 zeigt ja auch, dass der Nullindex unnatürlich ist. In C ist das anders, dort muss (musste?) man ja Arrays selbst verwalten. Da dynamische Arrays aber in FreePascal immer bei null anfangen, verwende ich das auch bei statischen Arrays meistens.

Der Fehler kann ja auch innerhalb der Schleife liegen. Beispiel:

Code: Alles auswählen

for ii:= 0 to length(arr)-1 
 do arr[ii]:= arr[ii]+ arr[ii+1]

Das passiert besonders leicht, wenn man versucht eine Schleife auf null zu 'biegen', die natürlicherweise andere Grenzen hätte.

Es gibt übrigens einen Wikiartikel zu diesem Thema (in Englisch):
http://wiki.freepascal.org/Defensive_pr ... techniques



Das der Fehler auch in der Schleife liegen kann tut aber nichts zur Sache

EDIT: missverstanden
Zuletzt geändert von Warf am So 15. Apr 2018, 22:17, insgesamt 1-mal geändert.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: Vorsicht mit Arrayindices

Beitrag von Timm Thaler »

Nur dass Du hier ein Problem konstruierst, welches so nicht existiert - oder nur in den Köpfen von eingefleischten C-Programmierern, die es nicht anders können.

Als ich meine Heizungssteuerung von C auf Pascal umgeschrieben habe, war ich froh endlich sinnvolle Array definieren zu können und nicht ständig zwischen Kanal 1..24 auf Arrayindex 0..23 und umgekehrt hin und herrechnen zu müssen. Das ist nicht weniger fehlerträchtig. Natürlich kann ich alle Kanäle von 0 anfangen lassen, aber ich verwende eine Hochsprache ja genau deswegen, damit sie mir das erspart, sonst kann ich gleich Assembler schreiben.

Und Arraygrenzen muss ich sowieso abfragen: Wenn über die RS232 die Anfrage kommt, sende mir den Wert von Kanal N, und N ist fälschlicherweise Null, dann ist bei dec(N) der Index auf ein Nullbasiertes Array genauso falsch wie ohne dec auf ein 1-basiertes. Ich muss also sinnigerweise immer obere und untere Arraygrenze prüfen.

Sinnvoll ist ein Nullbasiertes Array z.B. für einen Ringbuffer, wo man mit mod length für Operationen über den Buffer (gleitender Mittelwert...) immer schön im Bereich bleiben kann.

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: Vorsicht mit Arrayindices

Beitrag von kupferstecher »

Warf hat geschrieben:Das der Fehler auch in der Schleife liegen kann tut aber nichts zur Sache

Diese Art der Argumentation [...]

Das hättest du dir sparen können, erstmal die Argumente verstehen heißt die Devise.

Ein Beharren auf nullbasierte Schleifen erzwingt gegebenenfalls Umrechnungen innerhalb der Schleife, die genau für die besprochenen Bereichsüberschreitungen gefährdet sind. Auf dein E-Auto Beispiel bezogen: Du tust so als wäre die Stromerzeugung emissionslos.

Natürlich sollte man einen Standard für sich finden (durch die Nullbasierung bei dynamischen Schleifen ist der Standard vorgegeben), aber je nach konkreter Situation sollte man davon auch abweichen.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Vorsicht mit Arrayindices

Beitrag von Warf »

kupferstecher hat geschrieben:Das hättest du dir sparen können, erstmal die Argumente verstehen heißt die Devise.

Ein Beharren auf nullbasierte Schleifen erzwingt gegebenenfalls Umrechnungen innerhalb der Schleife, die genau für die besprochenen Bereichsüberschreitungen gefährdet sind. Auf dein E-Auto Beispiel bezogen: Du tust so als wäre die Stromerzeugung emissionslos.

Natürlich sollte man einen Standard für sich finden (durch die Nullbasierung bei dynamischen Schleifen ist der Standard vorgegeben), aber je nach konkreter Situation sollte man davon auch abweichen.


Ah sorry, hab dein beispiel auch nicht richtig verstanden, hatte irgendwie was ganz anderes im kopf

Antworten