Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Allgemeine Diskussion ueber Arrays "ohne Grenzen"

75 views
Skip to first unread message

Gunar Scholz

unread,
Feb 24, 1998, 3:00:00 AM2/24/98
to

Da sich die Diskussion im Thread "Offene Arrays" z.T. festgefahren hat,
und an anderen Stellen abdriftet, eroeffne ich hier mal einen neuen
Thread.

Wie allgemein bekannt ist, steht die Entwicklung ja nicht still, und so
fuhert Borland mit jeder Version von Pascal/Delphi (alles andere lass
ich hier ausser Betracht, dafuer gibt es eigene Newsgroups) auch neue,
mehr oder weniger konsequent umgesetzte Konzepte ein.

Ich will hier auf die offenen Arrays eigehen.

In der Parameter-Deklaration von Prozeduren und Funktionen kann man seit
BP7 Parameter vom Typ "array of Irgendwas" ohne Groessenangaben fuer das
Array deklarieren. Dies geht leider nicht in einer einfachen Typ- oder
Varablendeklaration. Hier ist zwingend notwendig eine Groessenangabe in
die Deklaration aufzunehmen.
Dazu zwei Beispiele:

Array als Parameter:
procedure TCanvas.Polygon(Points: array of TPoint);

Array in einer Typdeklaration:
type
PointArrayType = array [1..10] of TPoint;

Meiner Meinung nach haette Borland auch hier eine Deklaration ohne
Groessenangabe zulassen sollen, das wuerde, wie weiter unten zu sehen
ist, einige Kopfstaende ersparen.

Zur Erlaeuterung meiner Meinung greife ich auf das obige Beispiel
zurueck. Um der Methode Polygon die einzelnen Punkte zu uebergeben, gibt
es folgende Moeglichkeiten:
Wenn feststeht, dass das Polygon 3 Punkte haben soll, kann man ein Array
statisch deklarieren, es mit Werten fuellen und an Polygon uebergeben.

var
a: array [0..2] of TPoint;
begin
a[0] := Point(100,100);
a[1] := Point(150,200);
a[2] := Point(200,150);
Form.Canvas.Polygon(a);
end;

oder auch so:
Form.Canvas.Polygon([Point(100,100), Point(150,200), Point(200,150)]);

Daneben gibt es Faelle, bei denen man nicht weiss, aus wievielen Punkten
das Polygon gezeichnet werden soll. Nehmen wir ein Zeichenprogramm,
welches ein Bild nicht als Bitmap speichert, sondern jedes Element
einzeln mit Angabe seiner Eigenschaften (Koordinaten, Farbe, etc.).
Da ich als Programmierer nicht weiss, was fuer Gebilde der Anwender mit
meinem Programm erstellen will, brauche ich nun eine Moeglichkeit, an
die Methode Polygon beliebig viele Punkte zu uebergeben. Auch hier gibt
es wieder mehrere Moeglichkeiten der Umsetzung.
Ich deklariere ein ausreichend grosses statisches Array
var
a: array [0..99] of TPoint;
und uebergebe mit Hilfe der Funktion Slice einen Teilbereich des Arrays
an Polygon.
Das hat den Nachteil, dass der Anwender nur Polygone aus maximal 100
Punkten zeichnen kann, und ausserdem verschwende ich dabei wertvollen
Speicher im Datensegment oder auf dem Stack (je nachdem, ob a global
oder lokal deklariert ist).
Es gaebe da auch noch die Moeglichkeit, das Array auf dem Heap
anzulegen.
type
pa = ^ta;
ta = array [0..99] of TPoint;
var
a: pa;
begin
New(a);
...
Dispose(a);
end;

Damit wird zwar das Datensegment oder der Stack entlastet,
Speicherverschwendung bleibt es aber allemal. (Was dabei rauskommt, wenn
jeder Programmierer so mit dem Speicher umgeht, merkt man, wenn man mit
Windows und mehreren Win-Applikationen arbeitet und nicht genuegend
physikalischen Speicher installiert hat...)
Somit ist die beste Loesung, den Speicher nur nach Bedarf anzufordern.
Dafuer wuerde sich ein Array-Typ ohne vordefinierte Groessenangabe
eignen. Man deklariert:
type
pa = ^ta;
ta = array of TPoint;
var
a: pa;
und fordert je nach Bedarf Speicher an:
begin
GetMem(a, Anzahl_der_PolygonPunkte * SizeOf(TPoint));
...
FreeMem(a, Anzahl_der_PolygonPunkte * SizeOf(TPoint));
end;

Hier muss man als Programmierer unbedingt darauf achten, dass man nur in
den Speicherbereich zugreift, den man auch angefordert hat:
if x < Anzahl_der_PolygonPunkte then Zugriff auf Punkt x (a^[x])
Die Folge waere sonst, man ueberschreibt sich selbst Daten auf dem Heap,
die zu andere Teilen des Programms gehoeren. (Solche Fehler sind nicht
unbedingt einfach zu finden.) Im Extremfall jedoch greift man auf
Speicher zu, der gar nicht mehr zur eigenen Anwendung gehoert. Dies
allerdings lassen die Schutzmechanismen von Windows nicht zu, und man
erntet eine der bekannten Windows-Fehlermeldungen oder eine Exception.

Wie gesagt, laesst sich das Array leider nicht ohne Groessenangabe
deklarieren, und so muss man zu einer "Kruecke" greifen (bei der sich
nun die Geister scheiden, welche davon die bessere ist).

Borland wuerde das sicher so deklarieren:
(im Folgenden als 'erste Variante' bezeichnet)
type
ta = array [0..0] of TPoint;

Eine weitere Moeglichkeit ist (im Folgenden als 'zwite Variante'
bezeichnet), den oberen Grenzwert auf einen Wert zu setzen, der entweder
nie erreicht wird, oder den uns die Systembeschraenkungen vorgeben, wie
zum Beispiel MaxInt.
type
ta = array [0..MaxInt] of TPoint;

Das laesst sich in dem Fall aber so nicht compilieren, da MaxInt *
SizeOf(TPoint) 2GB ueberschreitet. Also muss man den Obergrenzen-Wert
selbst festlegen und hoffen, dass der Anwender ihn niemals
ueberschreiten wird (nicht sehr flexibel) oder errechnen:
const
MaxPoints = MaxInt div SizeOf(TPoint) -1;
type
ta = array [0..MaxPoints] of TPoint;

Dass MaxInt = 2GB ist, und damit auch die Groessenbeschraenkung fuer
zusammenhaengende Datenstrukturen repraesentiert ist hier Zufall.
Irgendwann gibt es die 2GB-Grenze nicht mehr, und MaxInt muss dann auch
nicht mehr mit der neuen Groessenbeschraenkung uebereinstimmen. Wie legt
man dann eine fuer jeden Fall ausreichende Obergrenze fest?
(Zugegeben, fuer das Polygon-Beispiel wird MaxPoints sicher nie erreicht
werden, es gibt aber sicher Faelle, bei denen das vorkommen kann.)

Soweit zur Deklaration. Im praktischen Einsatz, sprich beim Zugriff auf
den Array-Inhalt, ist zu beachten, dass in beiden Faellen zuerst
genuegend Speicher zur Verfuegung gestellt wird, den man dann mit Inhalt
fuellen kann. (GetMem... - Beispiel siehe oben) Dabei muss man (wiederum
in beiden Faellen) selbst darauf achten, nur auf die Array-Elemente
zuzugreifen, die mit Speicher hinterlegt sind (if x < ... - siehe oben).

Im Unterschied zur zweiten Variante tritt beim Zugriff auf das Element x
( 0 <= x < Anzahl_der_PolygonPunkte ) ein RangeCheck-Fehler auf. Der ist
aber fuer die weitere Ausfuehrung des Programmes nicht relevant, da ich
sowieso selbst drauf achte, mich nur in dem Bereich aufzuhalten, den ich
mit GetMem angefordert habe. Deshalb kann ich den RangeCheck-Fehler an
dieser Stelle ignorieren und den RangeCheck mittels Compilerschalter
fuer die betreffenden Zugriffe deaktivieren.

Jede der beiden Varianten hat also ihre Vor- und Nachteile, im Ergebnis
nehmen sie sich beide nichts. Fuer welche von beiden man sich
entscheidet, bleibt jedem selbst ueberlassen.
Ich finde, dass man bei der ersten Variante eher sieht, dass man es mit
einem etwas anders gearteten Array zu tun hat.

*

Anders waere das Problem loesbar, wenn man mit Pointern rechnen koennte,
zum Beispiel so:
var
a: ^TPoint;
index : Integer;
begin
GetMem(a, MaxPoints* SizeOf(TPoint));
if index < MaxPoints (a + index*SizeOf(TPoint))^ := Point(100,100);
...
Wie man sieht kommt man damit in keine RangeCheck-Konflikte. Doch
erstens geht das so (d.h. mit legalen Mitteln) nicht. Zweitens ist der
Programmieraufwand wesentlich hoeher und das Programm wird dadurch auch
nicht unbedingt leichter lesbar. (Und zu guter Letzt kann man es nun
auch nicht mehr an Polygon uebergeben.)

*

Wenn man nicht darauf angewiesen ist mit dem Typ 'array' zu arbeiten,
oder wenn man Daten unterschiedlicher Grosse indizierbar ablegen
moechte, kann bzw. muss man sich vom offenen Array trennen, und statt
dessen TList verwenden. Dieses Object bietet ausser einem RangeCheck
(genannt EListError-Exception), der nur zuschlaegt, wenn ich wirklich
danebenliege (Zugriff auf ein Element mit Index >= Items.Count), noch
ein paar weitere Methoden zur Datenverwaltung an, wie z.B. Sortierung
oder Suche nach einem bestimmten Eintrag. (Das hierbei andere Sachen
beachtet werden muessen, die nicht explizit in der Online-Hilfe erwaehnt
werden, will ich hier jetzt nicht weiter ausfuehren.)

*

Der Vollstaendigkeit halber seinen noch Low, High und Slice erwaehnt.
Bekommt man ein 'array of Irgendwas' als Parameter uebergeben, kann man
mit Low und High den unteren und oberen Grenzwert des Arrays
feststellen. Das nuetzt uns aber _so_ noch nicht viel, weder bei der
ersten noch bei der zweiten Variante. Beidesmal muss noch mittels Slice
angegeben werden, wie gross das Array in Wirklichkeit ist.

*

Ich hoffe, ein paar Probleme mit offenen Arrays allgemein verstaendlich
dargestellt zu haben, sowie auch meinen Standpunkt, warum ich zwar die
zweite Variante der Deklaration offener Arrays nicht grundsaetzlich
ablehne, sie aber auch nicht als das Nonplusultra und einzig Richtige
ansehe.

Vielen Dank fuers Durchhalten beim Lesen :-)

Felix

Rudy Velthuis

unread,
Feb 25, 1998, 3:00:00 AM2/25/98
to

Gunar Scholz schrieb in Nachricht <34F2C4B5...@pride.de>...


>Da sich die Diskussion im Thread "Offene Arrays" z.T. festgefahren
hat,
>und an anderen Stellen abdriftet, eroeffne ich hier mal einen neuen
>Thread.
>
>Wie allgemein bekannt ist, steht die Entwicklung ja nicht still, und
so
>fuhert Borland mit jeder Version von Pascal/Delphi (alles andere lass
>ich hier ausser Betracht, dafuer gibt es eigene Newsgroups) auch
neue,
>mehr oder weniger konsequent umgesetzte Konzepte ein.
>
>Ich will hier auf die offenen Arrays eigehen.

[snip ... Man kann ja die original message lesen. Die ist ziemlich
lang.]

Felix

Ich stimme voll mit dir überein.

Welche der beiden Varianten auch eingesetzt wird, man muß trotzdem
eine eigene Bereichsüberprüfung machen. Also sind beide Varianten
einigermaßen gleichwertig und also ziemlich abhängig von persönlichen
Präferenzen.

--
Rudy Velthuis
-------------------------------------------------
. Gladbeck, NRW Germany
. E-Mail: rvelthuis at cww dot de
-------------------------------------------------
. Join the JEDI Project: www.delphi-jedi.org
-------------------------------------------------

Sebastian Kanthak

unread,
Feb 25, 1998, 3:00:00 AM2/25/98
to

Halloechen Felix!

On Tue, 24 Feb 1998 14:01:41 +0100, Gunar Scholz <fe...@pride.de>
wrote:

>In der Parameter-Deklaration von Prozeduren und Funktionen kann man seit
>BP7 Parameter vom Typ "array of Irgendwas" ohne Groessenangaben fuer das
>Array deklarieren. Dies geht leider nicht in einer einfachen Typ- oder
>Varablendeklaration. Hier ist zwingend notwendig eine Groessenangabe in
>die Deklaration aufzunehmen.

[snip]

Deine Ausfuehrungen zu diesem Thema sind alle logisch und sicher waere
es auch wuenschenswert, dynamische wachsende und schrumpfende Arrays
zu haben. Du machst meiner Ansicht nach aber einen kleinen Denkfehler,
deswegen hier ein paar grundsaetzliche Ueberlegungen:
Wenn man ein "offenes Array" einer Prozedur oder Funktion (dumme
Unterscheidung) uebergibt, so wird der Compiler ja nur einen Zeiger
auf den Speicherbereich und die Grenzen uebergeben, also eine fest
definierte Menge Daten. Dieses Array hat jetzt auch nicht die
Faehigkeit zu schrumpfen oder zu wachsen, das besondere ist nur, dass
die Groesse vorher nicht bekannt ist.
Wuerde man solch ein offenes Array aber nun als Typ- oder
Variablendeklaration anlegen, muesste der Compiler nun eine voellig
anderen Code verwenden, da dieses Array jetzt ja dynamisch wachsen und
schrumpfen koennen muesste.
Es handelt sich hier also um zwei grundverschiedene Dinge, weswegen
ich es als sehr missverstaendlich empfinde, beides alls "offene
Arrays" zu bezeichnen. Offene Arrays sind die, bei denen
Groessenangaben mit uebergeben werden, das andere, was es noch nicht
gibt, wuerde ich besser als "dynamische Arrays" bezeichnen.
Nun stellt sich die Frage, ob so etwas wirklich in den Compiler
integriert werden sollte, schliesslich fordert es erheblich mehr Code
als eine simple Uebergabe der Array-Grenzen. Solche Aufgaben gehoeren
IMHO nicht eine (relativ) maschinennahe Sprache, sondern muessen von
der Laufzeitumgebung geloest werden. Und nichts anderes tut die VCL ja
mit der Klasse TList.

ciao Sebastian


Sebastian Kanthak
Email : sebastia...@muehlheim.de
Homepage: http://www.muehlheim.de/~skanthak/
PGP-Key : http://www.muehlheim.de/~skanthak/pgp/publickey.html

Lotto : Taxes for people who are bad in maths

Peter Hellinger

unread,
Feb 25, 1998, 3:00:00 AM2/25/98
to

Rudy Velthuis schrieb in Nachricht <34f41...@news2.cityweb.de>...

>Welche der beiden Varianten auch eingesetzt wird, man muß trotzdem
>eine eigene Bereichsüberprüfung machen. Also sind beide Varianten
>einigermaßen gleichwertig und also ziemlich abhängig von persönlichen
>Präferenzen.

Nein, nein und nochmals nein!!!

*Bereichs*überprüfungen macht der Compiler. Ob der Speicher auf den du
zugreifst auch alloziert ist, dafür bist du selbst verantwortlich. Die
entscheidende Frage ist: Wieviel Speicher sieht der Compiler für eine
Variable vor, deren Bereich 0..0 ist, und was passiert, wenn man dort einen
Wert <> 0 hineinspeichert? DAS ist die Crux!!! Nicht der allozierte
Speicher.


Beispiel: Ein Bereich von 0..0 belegt 1 Byte Speicher, ein Bereich von
0..999 2 Byte und ein Integer (D3) 4 Byte.

Was passiert wohl wenn ich ein Integer in einen Bereich für 0..0 speichere?
3 Bytes fremder Variablenspeicher werden überschrieben! Und diesen Fehler
merkt man nie, weil man Aufgrund des ARRAY [0..0] die Bereichsprüfung
abschalten muß.

Deshalb gilt: Arrays IMMER sauber mit einem Bereich deklarieren, egal ob man
nun dynamisch anfordert oder nicht. Und während des Beta-Phase IMMER mit
Rangecheck ON arbeiten, dann kann einem nichts passieren.
Bei einer getesteten Kundenversion kann man dann gerne den Rangcheck
abschalten um ein bisschen Code und Laufzeit zu sparen.

Nochmal: Es geht nicht um den allozierten Speicher, sondern um den
Array-Index.

Helli


Peter Draber

unread,
Feb 25, 1998, 3:00:00 AM2/25/98
to

Sebastian Kanthak schrieb in Nachricht
<34f3458e...@nntp.server.uni-frankfurt.de>...


>
>Deine Ausfuehrungen zu diesem Thema sind alle logisch und sicher waere
>es auch wuenschenswert, dynamische wachsende und schrumpfende Arrays

>zu haben. .....

Ja haben wir die denn nicht, in Unit System ganz laut und deutlich:
variable Array mit varianten Typen gar. Das ist doch schon mehr als
SUPERLUXUSBASIC.


Gunar Scholz

unread,
Feb 25, 1998, 3:00:00 AM2/25/98
to

Peter Hellinger wrote:
>
> *Bereichs*überprüfungen macht der Compiler.

Gemeint ist der Speicher-"Bereich", den ich mit GetMem angefordert habe.
Und um dessen Ueberschreitung kuemmert sich der Compiler in unserem Fall
nicht. Der Rangecheck-Fehler beim [0..0]-Array-Typ tritt ja zur Laufzeit
auf und da hat sich der Compiler schon laengst wieder zur Ruhe begeben.

> Ob der Speicher auf den du
> zugreifst auch alloziert ist, dafür bist du selbst verantwortlich.

Genau so sehe ich das auch, aber davor schuetzt mich der RangeCheck
nicht und deshalb ist es egal, ob ich da ein Konstrukt mit oder ohne
RangeCheck-Error waehle.

> Die entscheidende Frage ist: Wieviel Speicher sieht der Compiler für
> eine Variable vor, deren Bereich 0..0 ist, und was passiert, wenn man
> dort einen Wert <> 0 hineinspeichert? DAS ist die Crux!!! Nicht der
> allozierte Speicher.

Wer redet denn von einer Variablen? Es geht immer nur um eine
Typ-Deklaration. Eine Variable hat in Pascal/Delphi keinen Bereich, nur
eine Groesse. Nur das Array fasst Daten eines bestimmten Types zu einem
Bereich [x..y] zusammen.

> Beispiel: Ein Bereich von 0..0 belegt 1 Byte Speicher, ein Bereich von
> 0..999 2 Byte und ein Integer (D3) 4 Byte.

Wieviel Byte ein Array [0..0] belegt, kommt immer darauf an, aus was
fuer Typen das Array besteht. Ein Bereich, der von 0..0 geht und 1 Byte
Speicher belegt kann nur so aussehen:
var
a: Array [0..0] of Byte/Char;

> Was passiert wohl wenn ich ein Integer in einen Bereich für 0..0
> speichere? 3 Bytes fremder Variablenspeicher werden überschrieben!

Willst du etwa a[0] einen Integer-Wert zuweisen?

Das wurde ich dich bitten, mir zu zeigen, wie das programmiert werden
kann.

> Nochmal: Es geht nicht um den allozierten Speicher, sondern um den
> Array-Index.

An welcher Stelle bereitet denn der Index als solcher Probleme?

*

Nochmal zur Klarstellung:
Ich nutze die Array-Deklaration nur als Hilfsmittel, um indiziert auf
einen Speicherbereich zuzugreifen, den ich z.B. mittels GetMem fuer
meine Zwecke ausreichend dimensioniert anfordere und auch mit ReAllocMem
gegebenenfalls vergroessern oder verkleinern kann. Wie gross der
Speicherbereich ist und dass ich nicht uebertrete darueber wache ich
selbst. Dass Delphi unbedingt eine Groessenangabe bei einer
Array-Deklaration fordert, stoert dabei. Und auch, dass es diese
Grenzwerte ueberwachen will. Du umgehst das indem du das Array zu gross
dimensionierst und ich, indem ich diese Ueberwachung ausschalte.

Felix

Gunar Scholz

unread,
Feb 25, 1998, 3:00:00 AM2/25/98
to

Sebastian Kanthak wrote:
>
> Wenn man ein "offenes Array" einer Prozedur oder Funktion (dumme
> Unterscheidung) uebergibt, so wird der Compiler ja nur einen Zeiger
> auf den Speicherbereich und die Grenzen uebergeben, also eine fest
> definierte Menge Daten.

Kommt ganz drauf an, wie das im Prozedurkopf definiert ist (mit var,
const oder ohne). Wann was uebergeben wird steht in der D2-Hilfe unterm
Stichwort "Offene Array-Parameter".

> Dieses Array hat jetzt auch nicht die
> Faehigkeit zu schrumpfen oder zu wachsen, das besondere ist nur, dass
> die Groesse vorher nicht bekannt ist.

Die Groesse das uebergebenen Arrays, genauer gesagt, sein oberer und
unterer Grenzwert, kann innerhalb der Prozedur/Funktion mit Low bzw.
High abgefragt werden, und vor der Uebergabe mit Slice eingeschraenkt
werden. Wenn ich das Array incl. 'Abmessungen' einmal uebergeben habe,
kann ich es ohne Auswirkungen veraendern. Ich rufe die Prozedur/Funktion
auf, die macht irgendwas mit dem Array, und danach bin ich ja erst
wieder an der Reihe. Ein so uebergebenes Array wuerde ich nie innerhalb
der Prozedur/Funktion aendern. Wenn es als Wert-Parameter uebergeben
wurde hat das eh keinen Sinn, als konstanter Parameter auch nicht.
Selbst wenn es als Variablen-Parameter uebergeben wird, gehoert sich das
nicht. (Canvas.Polygon wuerde das auch nicht tun wollen :-)

> Wuerde man solch ein offenes Array aber nun als Typ- oder
> Variablendeklaration anlegen, muesste der Compiler nun eine voellig
> anderen Code verwenden, da dieses Array jetzt ja dynamisch wachsen und
> schrumpfen koennen muesste.

Hier kann ich deine Gedankengaenge nicht ganz nachvollziehen.
Moeglicherweise hat sich das aber durch meine obigen Ausfuehrungen schon
erledigt.

> Es handelt sich hier also um zwei grundverschiedene Dinge, weswegen
> ich es als sehr missverstaendlich empfinde, beides alls "offene
> Arrays" zu bezeichnen. Offene Arrays sind die, bei denen
> Groessenangaben mit uebergeben werden, das andere, was es noch nicht
> gibt, wuerde ich besser als "dynamische Arrays" bezeichnen.

Jein.
Auf der einen Seite hat Borland zwar die Moeglichkeit geschaffen ein
beliebig grosses Array an Prozeduren/Funktionen zu uebergeben und das
Ganze dann "offene Array-Parameter" genannt, andererseits aber nicht
definiert, wie man ein beliebig grosses Array zur Laufzeit erzeugen soll
(und wie das Ding genau zu heissen hat).
TList ist zwar schoen und gut, aber in dem Array, das intern fuer die
property Items verwendet wird, kann ich nur Pointer ablegen. Damit ist
das z.B. fuer das Polygon ungeeignet.

> Nun stellt sich die Frage, ob so etwas wirklich in den Compiler
> integriert werden sollte, schliesslich fordert es erheblich mehr Code
> als eine simple Uebergabe der Array-Grenzen.

Ich glaub nicht, dass dabei uebermaessig viel Code erzeugt wird. Auch
nehme ich an, dass Borland nicht in erster Linie den Programmierer mit
offenen Array-Parametern begluecken wollte, sondern dass sich das so als
beste Loesung ergab, in C geschriebene Windows-API-Funktionen
einigermassen pascal-konform zu kapseln. (Besonders, wenn ich mir die
API-Deklaration von Polygon anschaue.)

Felix

Sebastian Kanthak

unread,
Feb 26, 1998, 3:00:00 AM2/26/98
to

Halloechen!

Wirklich. Ich habe die Quelltexte der unit system leider nicht, aber
was meinst Du mit "variable Arrays", die dynamisch wachsend und
schrumpfen? Gibt es das wirklich schon in Pascal??
Die Varianten Typen mussten halt wegen dem blöden OLE/(D)COM (oder
heisst es jetzt ActiveX?) her, sonst sollte man sie wirlich nicht
benutzen. Und den Ausdruck "Superluxusbasic" meinteste Du hoffentlich
ironisch, für mich ist das naemlich der absolute Horror...

Peter Draber

unread,
Feb 26, 1998, 3:00:00 AM2/26/98
to

Sebastian Kanthak schrieb in Nachricht

<34f55915...@nntp.server.uni-frankfurt.de>...


>Halloechen!
>
>On Wed, 25 Feb 1998 21:02:30 -0100, "Peter Draber"
><dra...@berlin.snafu.de> wrote:
>Wirklich. Ich habe die Quelltexte der unit system leider nicht, aber
>was meinst Du mit "variable Arrays", die dynamisch wachsend und
>schrumpfen? Gibt es das wirklich schon in Pascal??
>Die Varianten Typen mussten halt wegen dem blöden OLE/(D)COM (oder
>heisst es jetzt ActiveX?) her, sonst sollte man sie wirlich nicht
>benutzen. Und den Ausdruck "Superluxusbasic" meinteste Du hoffentlich
>ironisch, für mich ist das naemlich der absolute Horror...

;-) da gehts den Menschen, wie den Leuten!

bei den Varianten gibt's auch variable Arrays, die können zur Laufzeit
gesetzt werden (vararraycreate([Anfang,ende],varaintentyp) ), und die können
beliebig umdeklariert werden. Der Nachteil: nur für Variantentypen
zulässig.


Rudy Velthuis

unread,
Feb 26, 1998, 3:00:00 AM2/26/98
to

Peter Hellinger schrieb in Nachricht <6d1plg$alc$1...@news.nacamar.de>...


>Rudy Velthuis schrieb in Nachricht <34f41...@news2.cityweb.de>...
>>Welche der beiden Varianten auch eingesetzt wird, man muß trotzdem
>>eine eigene Bereichsüberprüfung machen. Also sind beide Varianten
>>einigermaßen gleichwertig und also ziemlich abhängig von
persönlichen
>>Präferenzen.
>
>Nein, nein und nochmals nein!!!
>

>*Bereichs*überprüfungen macht der Compiler. Ob der Speicher auf den


du
>zugreifst auch alloziert ist, dafür bist du selbst verantwortlich.

Die
>entscheidende Frage ist: Wieviel Speicher sieht der Compiler für eine
>Variable vor, deren Bereich 0..0 ist, und was passiert, wenn man dort
einen
>Wert <> 0 hineinspeichert? DAS ist die Crux!!! Nicht der allozierte
>Speicher.
>
>

>Beispiel: Ein Bereich von 0..0 belegt 1 Byte Speicher, ein Bereich
von
>0..999 2 Byte und ein Integer (D3) 4 Byte.
>

>Was passiert wohl wenn ich ein Integer in einen Bereich für 0..0
speichere?

>3 Bytes fremder Variablenspeicher werden überschrieben! Und diesen
Fehler
>merkt man nie, weil man Aufgrund des ARRAY [0..0] die Bereichsprüfung
>abschalten muß.

Ich kann keinen Integer oder irgendwas in einen Bereich speichern,
höchstens in eine Variable vom Typ 0..0. Wenn ich versuche 65530 in so
eine Variable zu speichern, passiert nichts (auch ohne
Bereichsüberprüfung), als daß nur das unterste Byte gespeichert wird.

Probier doch einmal das folgende:

var
A: array[0..3] of Byte;
B: Integer;

begin
{$OPTIMIZATION OFF}
{$R-}
FillChar(A, Sizeof(A), 0);
B := 123456;
A[0] := B;
ShowMessage(Format('%3d %3d %3d %3d %8x', [A[0], A[1], A[2], A[3],
B]));
end.

Du siehst dann, daß A[1] bis A[3] nicht überschrieben werden. Es
passiert also nicht viel. Das hat nichts mit *Bereichsüberprüfung* zu
tun, sondern alles mit *Typüberprüfung*. Die bringst du hier
einigermaßen durcheinander. Nun ist A[0] kein Index, aber ein Byte,
das einen Wert erhält von einem Integer. Du siehst, das nur das Byte
betroffen ist.

>Deshalb gilt: Arrays IMMER sauber mit einem Bereich deklarieren, egal
ob man
>nun dynamisch anfordert oder nicht. Und während des Beta-Phase IMMER
mit
>Rangecheck ON arbeiten, dann kann einem nichts passieren.
>Bei einer getesteten Kundenversion kann man dann gerne den Rangcheck
>abschalten um ein bisschen Code und Laufzeit zu sparen.
>

>Nochmal: Es geht nicht um den allozierten Speicher, sondern um den
>Array-Index.

Wenn ich es richtig verstehe, dann meinst du, daß bei einem Bereich
von 0..0 nur 1 Byte für den Index zulässig ist, weil SizeOf(0..0) = 1.
Das stimmt auch nicht. Ich kann (mit $R-) zuverlässig das 258. Zeichen
eines Strings referenzieren, der mit array[0..0] of Char deklariert
wurde.

Probier das doch mal:

const
X = '0123456789012345678901234567890123456789'; // 40 Zeichen
Y = X + X + X + X + X + X + X + X + X + X + X + X + 'ABCDEFGHIJ'; //
490 Zeichen.

type
TP = record
Z: Integer;
X: array[0..0] of Char;
end;
PP = ^TP;

var
Q: PP;
B, C: Integer;

begin
GetMem(Q, 500);
FillChar(Q^, 500, #0);
StrCopy(PChar(@Q^.X), Y); // Nur mit einem String füllen
B := 481; C := 489;
{$R-}
ShowMessage(Format('%s %s', [Q^.X[B], Q^.X[C]]));
{$R+}
end.

Das hier oben ist eine typische Anwendung für den [0..0] Trick. Die
const-Deklaration ist ja nur dazu da, einen 490 Byte langen String zu
definieren. Ich fülle dann Q^.X mit den gewünschten Zeichen per
StrCopy. Normalerweise ist TP ja einen variablen Record, der von
irgendeiner Windows-API zurückgegeben wird. B und C sind beide vom Typ
Integer (4 Byte) und enthalten einen Wert über 255, also belegt der
Index auch mindestens 2 Byte. Trotzdem zeigt ShowMessage B und J and
(wie erwünscht).

Die Erkärung ist einfach: Der Index wird mit (16bit oder 32bit)
Registern berechnet. Da paßt jeder Integer-Wert hinein. Hierfür wird
keine Variable verwendet, die irgendwo (Stack, Heap) alloziert werden
müßte. Man kann deshalb auch einen Integer-Wert über den Bereich
hinaus verwenden. Es wird garantiert nichts überschrieben, es ist nur
eine verdeckte Form von Zeiger-Arithmetik. Und genau dafür sind die
Deklarationen mit [0..0] für Arrays von variabler Länge. Diese Arrays
müssen natürlich das letzte Array im Record sein, aber das gilt bei
deiner Deklarationsweise ja auch.

Also imho vertust du dich gewaltig.

MfG
Rudy Velthuis

Peter Hellinger

unread,
Feb 26, 1998, 3:00:00 AM2/26/98
to

Gunar Scholz schrieb in Nachricht <34F48915...@pride.de>...


>Genau so sehe ich das auch, aber davor schuetzt mich der RangeCheck
>nicht und deshalb ist es egal, ob ich da ein Konstrukt mit oder ohne
>RangeCheck-Error waehle.


Nein, ist es nicht wie ich eben in meiner Mail an Rudy mehr lang als breit
schrieb.

>Wer redet denn von einer Variablen?

ICH.

> Es geht immer nur um eine Typ-Deklaration.

NEIN.

>Eine Variable hat in Pascal/Delphi keinen Bereich, nur eine Groesse.

FALSCH. Und zwar grundlegend.

>Wieviel Byte ein Array [0..0] belegt, kommt immer darauf an, aus was
>fuer Typen das Array besteht. Ein Bereich, der von 0..0 geht und 1 Byte
>Speicher belegt kann nur so aussehen:
>var
> a: Array [0..0] of Byte/Char;


FALSCH.

>> Was passiert wohl wenn ich ein Integer in einen Bereich für 0..0
>> speichere? 3 Bytes fremder Variablenspeicher werden überschrieben!
>

>Willst du etwa a[0] einen Integer-Wert zuweisen?

>Das wurde ich dich bitten, mir zu zeigen, wie das programmiert werden
>kann.


Ah! DAS bezweifelst du, das das geht? Warum?

>> Nochmal: Es geht nicht um den allozierten Speicher, sondern um den
>> Array-Index.
>

>An welcher Stelle bereitet denn der Index als solcher Probleme?


Können wir uns soweit verständigen, daß wenn wir in zwei Bytes Speicher
einen Wert ablegen, der 4 Bytes umfassen muß um ihn darzustellen, das wir
dann ein kleines Problem habe, was wir mit den überzähligen Bytes tun
sollen?

>selbst. Dass Delphi unbedingt eine Groessenangabe bei einer
>Array-Deklaration fordert, stoert dabei.

Tut es nicht, wenn man es richtig macht.

> Du umgehst das indem du das Array zu gross
>dimensionierst und ich, indem ich diese Ueberwachung ausschalte.


Nein. Ich dimensioniere den Array-Typ auf seine maximale Größe und stelle
damit sicher, daß der Compiler eine genügend grosse Variable hat um jeden
beliebigen Indexwert bei der Adressberechnung des Zugriffs zwischenspeichern
zu können. Und ich stelle damit sicher, daß das Konstrukt unabhängig von
Compilerschaltern läuft.

Helli

PS: Ich fasse es einfach nicht, daß man hier simpelste Grundlagen geradezu
predigen muß. 8-(


Peter Hellinger

unread,
Feb 26, 1998, 3:00:00 AM2/26/98
to

Gunar Scholz schrieb in Nachricht <34F49ADB...@pride.de>...


>Kommt ganz drauf an, wie das im Prozedurkopf definiert ist (mit var,
>const oder ohne). Wann was uebergeben wird steht in der D2-Hilfe unterm
>Stichwort "Offene Array-Parameter".


Es gibt zwei Methoden, wie Parameter übergeben werden. "Call by Value" und
"Call by Reference". Offene Arrays werden immer als Call by Reference
übergeben. Call by Value geht nicht, weil man zur Compiletime wissen müsste
wie groß das Array ist. Pascal wendet hier einen Trick im Compiler an: Die
Syntax ist insofern erweitert, daß man einen Openarray auch als Call by
Value übergeben kann. Tatsächlich wird aber Call by Reference verwendet, und
der Compiler überwacht den richtigen Zugriff.

Helli


Rudy Velthuis

unread,
Feb 26, 1998, 3:00:00 AM2/26/98
to

Gunar Scholz schrieb in Nachricht <34F48915...@pride.de>...

>Wer redet denn von einer Variablen? Es geht immer nur um eine
>Typ-Deklaration. Eine Variable hat in Pascal/Delphi keinen Bereich,
nur


>eine Groesse. Nur das Array fasst Daten eines bestimmten Types zu
einem
>Bereich [x..y] zusammen.


Du meinst es gut, sagst es aber leider falsch. Eine Variable hat einen
Bereich, wenn die Variable von einem ordinalen Typ ist. Ein Byte hat
den Bereich 0..255, Ein Char #0..#255, ein Word 0..65535, usw.

>> Beispiel: Ein Bereich von 0..0 belegt 1 Byte Speicher, ein Bereich
von
>> 0..999 2 Byte und ein Integer (D3) 4 Byte.

>Wieviel Byte ein Array [0..0] belegt, kommt immer darauf an, aus was


>fuer Typen das Array besteht. Ein Bereich, der von 0..0 geht und 1
Byte
>Speicher belegt kann nur so aussehen:
>var
> a: Array [0..0] of Byte/Char;

Auch hier verstehst du Peter falsch. Peter meint: SizeOf(0..0) = 1 und
SizeOf(0..999) = 2. Das stimmt sogar.

>> Was passiert wohl wenn ich ein Integer in einen Bereich für 0..0
>> speichere? 3 Bytes fremder Variablenspeicher werden überschrieben!
>
>Willst du etwa a[0] einen Integer-Wert zuweisen?
>
>Das wurde ich dich bitten, mir zu zeigen, wie das programmiert werden
>kann.

Geht auch: {$R-} A[0] := B (wobei B ein Integer ist, siehe meine
Antwort auf Peters Message in diesem Thread; hab's ausprobiert!).

>> Nochmal: Es geht nicht um den allozierten Speicher, sondern um den
>> Array-Index.

>An welcher Stelle bereitet denn der Index als solcher Probleme?

Peter meinte das ganz anders als wir. Er meinte ein Bereich 0..0 hat
einen SizeOf von 1. Wenn ich nun einen Integer benutze (SizeOf = 4),
würde ich also 3 benachbarte Bytes (des Index!, nicht des Arrays)
überschreiben. Das stimmt allerdings nicht, da die Indexberechnung nur
Zeigerarithmetik ist, die nirgends gespeichert wird (außer im
Index-Register der CPU). Es wird gar nichts überschrieben, nur eine
Adresse berechnet. Das habe ich Peter auch in der anderen Message
klargemacht.

MfG

Peter Hellinger

unread,
Feb 27, 1998, 3:00:00 AM2/27/98
to

Rudy Velthuis schrieb in Nachricht <34f5d...@news1.cityweb.de>...

>Ich kann keinen Integer oder irgendwas in einen Bereich speichern,
>höchstens in eine Variable vom Typ 0..0. Wenn ich versuche 65530 in so
>eine Variable zu speichern, passiert nichts (auch ohne
>Bereichsüberprüfung), als daß nur das unterste Byte gespeichert wird.


Aua.

>Du siehst dann, daß A[1] bis A[3] nicht überschrieben werden.

Schau dir mal im CPU-Fenster an, was für einen Code der Compiler erzeugt.
Natürlich überschreibt die Zuweisung nicht den Array-Inhalt, weil zur
Zuweisung der Compiler den Wert zum Array in ein Register lädt. Das wird
aber nur Bytebreit wieder zurückgeschrieben, gelle?

>Es passiert also nicht viel. Das hat nichts mit *Bereichsüberprüfung* zu
>tun, sondern alles mit *Typüberprüfung*. Die bringst du hier einigermaßen
>durcheinander.

Aua, aua.

Typprüfung macht der Compiler beim Übersetzen (deshalb kasst du auch bei
eingeschaltetem Rangecheck deinen Array [0..0] nicht übersetzen, wenn du mit
Konstanten arbeitest. Bereichsprüfungen sind Code im Compilat, die zur
Laufzeit prüfen, ob der eine Wert in den anderen paßt.

>Wenn ich es richtig verstehe, dann meinst du, daß bei einem Bereich
>von 0..0 nur 1 Byte für den Index zulässig ist, weil SizeOf(0..0) = 1.

>Das stimmt auch nicht. Ich kann (mit $R-) zuverlässig das 258. Zeichen
>eines Strings referenzieren, der mit array[0..0] of Char deklariert
>wurde.


Nein bitte! Lass es, du redest dich um kopf und Kragen. Du kannst es nicht,
weil der Array gar kein 258 Zeichen hat, sondern nur ein einziges!!! Schnall
das endlich mal!!!

>Das hier oben ist eine typische Anwendung für den [0..0] Trick.

Das ist typischer Pfusch von Leuten, die nicht wissen was sie tun.

>Die Erkärung ist einfach: Der Index wird mit (16bit oder 32bit)
>Registern berechnet.

Wo in der Delphi-Dokumentation steht das?

>Also imho vertust du dich gewaltig.


Ja. Du hast Recht und ich meine Ruhe. Ich hoffe bloß niemals in die
Verlegenheit zu kommen, áuf eines deiner Programme angewiesen zu sein.


Peter Draber

unread,
Feb 27, 1998, 3:00:00 AM2/27/98
to


>>Die Erkärung ist einfach: Der Index wird mit (16bit oder 32bit)
>>Registern berechnet.
>
>Wo in der Delphi-Dokumentation steht das?
>


Ich will da auch noch meinen Senf loswerden!

Die nachfolgenden Ausführungen beziehen sich auf die Untersuchung des
Index und welche Auswirkunungen es hat, verschiedene Indextypen
einzusetzen.

Die Delphi-Dokumentation sagt so inetwa , dass typgerecht
indiziert werden muß. d.h. Wenn = Array[Byte] of xx dann
darf nicht mit Word oder Longint indiziert werden

------- Zitat: ----
Array Indizes
Der Index eines Arrays ermöglicht den Zugriff auf eine spezielle Komponente
eines Arrays.
Der Indexausdruck wählt die Komponenten in der jeweils entsprechenden
Dimension des Arrays aus. Für Array-Indizes gibt es folgende
Einschränkungen:
Die Anzahl der Ausdrücke kann die Anzahl der Indextypen in der
Array-Deklaration nicht überschreiten.
Der Typ jedes Ausdrucks muß zuweisungskompatibel zum entsprechenden
Indextyp sein.
---- ende ---

sogut, soweit:
Nun hab ich mir aber mal den Code angesehen in 32 bit.
(bitte nicht gleich wieder schreien, daß es auch 16 bit gibt!)

AB : Array[Byte] of Integer;
INDEX : WORD;
WERT : Byte;
// alles global

AB[INDEX] := WERT;

erzeugt:
xor EAX,EAX
mov AL,[adresse WERT]
mov EDX,[ADRESSE Index] !!!! nix WORD
mov [ + adresse AB ], EAX

---- Delphi Zitat -----
Anmerkung
Unabhängig vom Status des $A-Befehls werden Variablen
und Konstanten immer auf optimalen Zugriff ausgerichtet
----------------
was heißt Word wird zu LongInt

na gut, nächster Versuch um den Compiler zu locken:

Index : Array[0..10] of Word;

AB [ Index[1] ] := wert;

und siehe da, da kommt er dann mit
movzx EDX, [Adresse von Index[1] ]
// movzx bedeutet Zieloperand links mit Nullen füllen
// also sauberer 32 bit Übergang

Fazit :
- in 32 bit Welt wird nur mit 32bit Index gearbeitet !
je nachdem wie der Index zugewiesen wird,
er wird immer auf 32 bit ergänzt.
(sonst funktioniert ja die Adressierung nicht)

- Theorie ist das eine, die Praxis das andere.

Heinz Zastrau

unread,
Feb 27, 1998, 3:00:00 AM2/27/98
to

Hallo Peter,

Peter Hellinger schrieb in Nachricht <6d4rrk$icd$4...@news.nacamar.de>...

>PS: Ich fasse es einfach nicht, daß man hier simpelste Grundlagen geradezu
>predigen muß. 8-(

Nein, nein und nochmals nein, hier muß man keine simpelsten Grundlagen
peredigen. Ein netter Hinweiß das bei dieser oder jener Lösung noch dies und
das zu beachten ist reicht völlig aus. Den Rest muß jeder mit sich selbst
und evt. noch mit seinen Kollegen abmachen. Dies ist schließlich nicht die
de.comp.lang.pascal.delphi.oberlehrer News-Group.

L A S S D A S P R E D I G E N E I N F A C H !!! Ich wäre dir
sooooooooooooo dankbar.

Ciao Heinz

Peter Hellinger

unread,
Feb 27, 1998, 3:00:00 AM2/27/98
to

Rudy Velthuis schrieb in Nachricht <34f6a...@news2.cityweb.de>...


>Das stimmt allerdings nicht, da die Indexberechnung nur
>Zeigerarithmetik ist, die nirgends gespeichert wird (außer im
>Index-Register der CPU). Es wird gar nichts überschrieben, nur eine
>Adresse berechnet. Das habe ich Peter auch in der anderen Message
>klargemacht.


Hast du das schriftlich? Steht das in irgendeiner Unterlage von Borland oder
gar Intel? Woher weißt du das das über D1 bis D3 und beim kommenden D4 noch
so ist? Und verhält sich der Code auf einem 386er, 486er, Pentium und
Pentium2 gleichartig?

Ein Beispiel: Ich habe hier noch Sourcen in Gebrauch, die habe ich vor 20
Jahren mit TP 2.0 unter CP/M entwickelt, und verwende sie unter DOS, Windows
und sogar auf 68k-Hardware. Glaubst du, die könnte man so verwenden, wenn
sich so auf die Eigenheiten eines Compilers verlassen würde?

Helli


Gunar Scholz

unread,
Feb 27, 1998, 3:00:00 AM2/27/98
to

Da ich mangels geeigneten Progammes nicht nachsehen kann, was der
Compiler unter D2 nun genau erzeugt, glaube ich zunaechst einmal, was in
der D2-Hilfe steht:

"Für einen offenen Array-Wert-Parameter erzeugt der Kompiler eine lokale
Kopie des aktuellen Parameters im Stack-Bereich der Prozedur oder
Funktion. Deshalb achten Sie darauf, den lokalen Speicher nicht zu
überlasten, wenn Sie große Arrays als offene Array-Wert-Parameter
übergeben. Um sicherzugehen, daß der Stack nicht überläuft, verwenden
Sie besser var of const, wenn Sie offene Array-Wert-Parameter
übergeben."

Ob du Recht hast oder die Hilfe muesste ich mittels eines Programmes
ermitteln.

Nehmen wir Delphi 2 und dieses Programm: (nur die relevanten
Ausschnitte)

{$MAXSTACKSIZE $00010000} // ich verkleinere den Stack mal etwas

procedure TForm1.x(a: array of Integer);
begin
Edit1.Text := IntToStr(Low(a));
Edit2.Text := IntToStr(High(a));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
a: array [0..10000] of Integer;
begin
a[0] := 1; //irgendeine belanglose Zuweisung
x(Slice(a, 1000)); // <--- "markierte Zeile"
end;

Und so funktionierts (auf Knopfdruck):

Als erstes wird ein Array auf dem Stack angelegt.
Dann uebergebe ich mittels Call-by-Value 1000 Elemente dieses Arrays an
'x'.
Soweit so gut, nichts (Schlimmes) passiert. Die Edit-Felder zeigen 0 und
999 an.
Erhoehe ich nun in der "markierten Zeile" die Anzahl der uebergebenen
Elemente auf 10000 gibts beim naechsten Programmlauf einen
"Stack-Überlauf".

Und? Wer hat Recht?

Felix

Gunar Scholz

unread,
Feb 27, 1998, 3:00:00 AM2/27/98
to

Rudy Velthuis wrote:
>
[einige Erklaerungen]

Wenn du das so sagst, dann wird mir einiges an Peters Argumentation
klar.

> Peter meinte das ganz anders als wir. Er meinte ein Bereich 0..0 hat
> einen SizeOf von 1. Wenn ich nun einen Integer benutze (SizeOf = 4),
> würde ich also 3 benachbarte Bytes (des Index!, nicht des Arrays)

> überschreiben. Das stimmt allerdings nicht, da die Indexberechnung nur


> Zeigerarithmetik ist, die nirgends gespeichert wird (außer im
> Index-Register der CPU). Es wird gar nichts überschrieben, nur eine
> Adresse berechnet. Das habe ich Peter auch in der anderen Message
> klargemacht.

Nun kommen wir einer Einigung schon ein ganzes Stueck naeher, wenn er
seinen Denkfehler bei der 'Index-Groesse' (oder heisst es besser
Index-Breite?) einsieht. Da du ja nun schon den Sachverhalt beschrieben
hast, kann ich mir auch Beispiele zum Index-Handling in Pascal und deren
Umsetzung durch den Compiler sparen.

Felix

Gunar Scholz

unread,
Feb 27, 1998, 3:00:00 AM2/27/98
to

Peter Hellinger wrote:
>
> Gunar Scholz schrieb in Nachricht <34F48915...@pride.de>...
> >Wer redet denn von einer Variablen?
> ICH.

Wenn du von einem
var
a: array [x..y] of Irgendwas;
sprichst, dann ist der RangeCheck natuerlich sinnvoll, das habe ich auch
nie bestritten. Nur bei unserem Array auf dem Heap nicht. (Ueber deinen
"Index-Fehler" hat ja Rudy schon an anderer Stelle etwas geschrieben.)

> > Es geht immer nur um eine Typ-Deklaration.

> NEIN.
was ist denn das sonst?
type
ta = array [0..0] of Irgendwas;

> >Eine Variable hat in Pascal/Delphi keinen Bereich, nur eine Groesse.

> FALSCH. Und zwar grundlegend.

nun gut, sie hat einen _Werte_-Bereich. Trotzden heisst es SizeOf und
nicht RangeOf. :-)

> >Das wurde ich dich bitten, mir zu zeigen, wie das programmiert werden
> >kann.

> Ah! DAS bezweifelst du, das das geht? Warum?

Ich bat dich um ein Beispiel, das haette mir sicher gezeigt, wie du es
meinst... (Ein Beispiel sagt mehr, als tausend missverstaendliche
Worte...)

> Können wir uns soweit verständigen, daß wenn wir in zwei Bytes Speicher
> einen Wert ablegen, der 4 Bytes umfassen muß um ihn darzustellen, das wir
> dann ein kleines Problem habe, was wir mit den überzähligen Bytes tun
> sollen?

ja, das stimmt, trifft aber nicht auf den Index zu, wie Rudy schon
schrieb.

> >Dass Delphi unbedingt eine Groessenangabe bei einer
> >Array-Deklaration fordert, stoert dabei.
> Tut es nicht, wenn man es richtig macht.

wie macht man es denn richtig, wenn nicht so: array [x..y] of ...

*

> PS: Ich fasse es einfach nicht, daß man hier simpelste Grundlagen
> geradezu predigen muß. 8-(

Auch was Grundlegendes:

Ist denn das eine Art, in Grossbuchstaben (das bedeutet in geschriebener
Unterhaltung "schreiend") mit einzelnen Worten ("FALSCH", "NEIN") zu
antworten, ohne das zu begruenden?

Felix

Gunar Scholz

unread,
Feb 27, 1998, 3:00:00 AM2/27/98
to

Peter Drabner schrieb:

> Fazit :
> - in 32 bit Welt wird nur mit 32bit Index gearbeitet !
> je nachdem wie der Index zugewiesen wird,
> er wird immer auf 32 bit ergänzt.
> (sonst funktioniert ja die Adressierung nicht)

genau so ein Beispiel, allerdings in 16 Bit, haette ich auch gepostet.
In 16 Bit wird sogar ein 32-Bit-LongInt-Index-Zugriff auf 16 Bit
"kastriert".

var
a1: array [0..200] of Integer;
li : LongInt;
begin
...
li := $64;
a1[li] := 32000;
...
end.

sieht dann so aus:

PROGRAM.22: li := $64;
cs:0035 C706E6016400 mov word ptr [01E6],0064 Low-Teil von li
cs:003B C706E8010000 mov word ptr [01E8],0000 High-Teil von li
PROGRAM.23: a1[li] := 32000;
cs:0041 8B3EE601 mov di,[01E6] di ist ein 16-Bit-Register
cs:0045 D1E7 shl di,1
cs:0047 C7855000007D mov word ptr [di+0050],7D00

hier noch ein Auszug aus dem map-File:

Address Publics by Value
0060:0050 a1
0060:01E6 li

Interessant ist auch folgender Fall:

PROGRAM.22: li := $10064;
cs:0035 C706E8016400 mov word ptr [01E6],0064
cs:003B C706EA010100 mov word ptr [01E8],0001
PROGRAM.23: a1[li] := 32000;
cs:0041 8B3EE801 mov di,[01E6]
cs:0045 D1E7 shl di,1
cs:0047 C7855200007D mov word ptr [di+0052],7D00

ein WriteLn(a1[$64]); erzeugt ein '32000' auf dem Bildschirm.

Dieser Code wurde mit ausgeschaltetem RangeCheck erzeugt. Mit $R+ ist er
etwas laenger und es gibt selbstverstaendlich einen in diesem Fall
berechtigten und sinvollen Runtime-Error 201 - "Range check error".

Also liebe Kinder, macht sowas zu Hause nur nach, wenn ihr wisst, was
ihr da tut. :-)

Felix


Rudy Velthuis

unread,
Feb 27, 1998, 3:00:00 AM2/27/98
to

Peter Hellinger schrieb in Nachricht <6d4ulk$s1o$1...@news.nacamar.de>...

Wenn ich mit konstanten Indizes (außer 0) arbeiten kann, brauche ich
keine
[0..0] (oder in deinem Fall eine [0..MaxIndex]) Deklaration, da ich
dann wohl weiß wie groß das Array sein wird.

>>Wenn ich es richtig verstehe, dann meinst du, daß bei einem Bereich
>>von 0..0 nur 1 Byte für den Index zulässig ist, weil SizeOf(0..0) =
1.
>
>>Das stimmt auch nicht. Ich kann (mit $R-) zuverlässig das 258.
Zeichen
>>eines Strings referenzieren, der mit array[0..0] of Char deklariert
>>wurde.
>
>
>Nein bitte! Lass es, du redest dich um kopf und Kragen. Du kannst es
nicht,
>weil der Array gar kein 258 Zeichen hat, sondern nur ein einziges!!!
>Schnall das endlich mal!!!

Das Array hat sogar möglicherweise mehr, nur die Deklaration dafür
nicht. Dein Array hat ja auch nicht 2GB oder?

>>Das hier oben ist eine typische Anwendung für den [0..0] Trick.
>
>Das ist typischer Pfusch von Leuten, die nicht wissen was sie tun.

Das Wort Pfusch ist wohl sehr hart. Dann wissen wahrscheinlich die
Programmierer von Borland oder Microsoft auch nicht was sie tun. Das
M$ manchmal pfuscht, glaube ich noch, aber bei Borland kommt mir das
schon seltsamer vor ;)

>>Die Erkärung ist einfach: Der Index wird mit (16bit oder 32bit)
>>Registern berechnet.
>
>Wo in der Delphi-Dokumentation steht das?

Du erwähntest schon einmal das Assembler-Fenster. Schau doch da mal
rein.

Kennst du nur Delphi? Oder weißt du wirklich nicht wie ein
(eindimensionales) Array referenziert wird? Das ist für viele Compiler
gleich (ob C oder C++ oder Visual Pascal [OS/2] oder Delphi).

Was hältst du von folgendem Code:

var
I: Integer;
A: array[0..100] of Byte;
begin
for I := 0 to 100 do
A[I] := Random(100);
end;

Einen ähnlichen Code hast du bestimmt schon einmal benutzt (steht in
fast jedem Anfängerbuch). Dein Index (I) ist ein Integer. Random gibt
einen Integer zurück. Der Bereich für das Array ist aber nur 0..100
(also nimmt maximal 1 Byte ein). Trotzdem gibt es in keinem
Pascal-Compiler einen Fehler, sowohl beim Kompilieren als zur Laufzeit
(vorausgesetzt, "Random" und "Byte" sind bekannt, natürlich).

Also kann ich sehr wohl mit einem 32bittigen Wert ein Array
referenzieren, daß nur einen Bereich (Subrange) hat, der 1 Byte
einnimmt (probier es: SizeOf(0..0) = 1!). Auch kann ich ein einem
Byte-Array einen Wert speichern, der als Integer deklariert ist.

Falls ich aber statt "0 to 100" nun "0 to 101" geschrieben hätte,
würde ein Laufzeitfehler auftreten (bei eingeschaltetem Range-Check).

Und warum?

Weil der Compiler etwas kompiliert, das ungefähr folgendes macht:

- Berechne Random(100).
- Nehme einen Zeiger auf die Basis des Arrays.
- Teste, ob Index im Bereich 0..100 liegt
... und jetzt kommt's:
- Addiere zum Zeiger die Zahl Index * Elementgroesse.
- Schreibe das unterste Byte von EAX (Resultat von Random) in das vom
Zeiger Referenzierte Byte.

Der Optimizer würde einige Schritte umändern, da es viel einfacher ist
(in dieser Schleife), den Zeiger nur einmal zu laden und mit jedem
Durchgang zu inkrementieren. Im Prinzip wird aber ein Array immer
ähnlich wie oben referenziert. Schau es doch einfach nach im
Assembler-Fenster.

Nun kannst du natürlich sagen, daß das hier ein Array fester Größe
ist. Das stimmt. Das gleiche kann ich aber auch bei einem Array
variabler Größe machen (warum auch nicht?).

>>Also imho vertust du dich gewaltig.
>
>
>Ja. Du hast Recht und ich meine Ruhe. Ich hoffe bloß niemals in die

>Verlegenheit zu kommen, auf eines deiner Programme angewiesen zu
sein.

Ich sage nicht daß meine [0..0] Methode die *einzig* richtige ist. Du
sagst aber das die [0..MaxIndex] Methode die einzig richtige ist. Das
ist der Unterscheid zwischen uns. Deine favorite Methode funktioniert,
meine aber auch. Ich hasse es nur für unfähig verkauft zu werden.

--
Rudy Velthuis


Rudy Velthuis

unread,
Feb 27, 1998, 3:00:00 AM2/27/98
to

Peter Draber schrieb in Nachricht
<6d6bd4$3kn$1...@unlisys.unlisys.net>...


>
>Ich will da auch noch meinen Senf loswerden!
>
>Die nachfolgenden Ausführungen beziehen sich auf die Untersuchung des
>Index und welche Auswirkunungen es hat, verschiedene Indextypen
>einzusetzen.
>

>Fazit :
>- in 32 bit Welt wird nur mit 32bit Index gearbeitet !
> je nachdem wie der Index zugewiesen wird,
> er wird immer auf 32 bit ergänzt.
> (sonst funktioniert ja die Adressierung nicht)
>

>- Theorie ist das eine, die Praxis das andere.


Wahrscheinlich jeder hat schon einmal ein Array in einer Schleife
gefüllt, die eine Laufvariable vom Typ Integer hatte. Diese
Integervariable wurde dann als Index benutzt. Das war in jeder Version
von Pascal, die ich kenne (nicht nur auf Intel-Maschinen, auch auf
Z80-, 6502- und 68000-Maschinen), möglich. Das ist wahrscheinlich
sogar ISO-Pascal-Standard (da bin ich mir aber nicht ganz sicher).
Einige Pascals haben nicht einmal eine ausschaltbare
Bereichsüberprüfung. Also kann der Index wohl immer ein Integer sein,
egal wie groß Integer ist, und wie groß das Array ist.

Also verwundert mich dein Fazit gar nicht :-)

Ciao
--
Rudy Velthuis

Matthias Watermann

unread,
Feb 27, 1998, 3:00:00 AM2/27/98
to

felix schrieb am 27.02.98 in <34F6E284...@pride.de>:

> [...]


> {$MAXSTACKSIZE $00010000} // ich verkleinere den Stack mal etwas
>
> procedure TForm1.x(a: array of Integer);

Warum ohne "Const"?

> begin
> Edit1.Text := IntToStr(Low(a));
> Edit2.Text := IntToStr(High(a));
> end;
>
> procedure TForm1.Button1Click(Sender: TObject);
> var
> a: array [0..10000] of Integer;
> begin
> a[0] := 1; //irgendeine belanglose Zuweisung
> x(Slice(a, 1000)); // <--- "markierte Zeile"
> end;
>

> [...]


>
> Erhoehe ich nun in der "markierten Zeile" die Anzahl der uebergebenen
> Elemente auf 10000 gibts beim naechsten Programmlauf einen
> "Stack-Überlauf".

Hast Du's auch mal ohne 'Slice()' (das erst ab D2
vorhanden ist) versucht? Womöglich ist diese Funktion (für die
ich selbst in den ASM-Dateien von D2 keinen Quell-Kode gefunden
habe) für das 'Phänomen' verantwortlich? Vielleicht kopiert die
ja den ausgewählten Bereich um, bevor sie ihn an die Ziel-Routine
übergibt?

--
Matthias

Liebe Deine Feinde, aber sei schneller als sie.

Rudy Velthuis

unread,
Feb 28, 1998, 3:00:00 AM2/28/98
to

Matthias Watermann schrieb in Nachricht
<6oe9L...@dfg.oln.ComLink.APC.org>...


>
>felix schrieb am 27.02.98 in <34F6E284...@pride.de>:
>
>> [...]
>> {$MAXSTACKSIZE $00010000} // ich verkleinere den Stack mal etwas
>>
>> procedure TForm1.x(a: array of Integer);
>
> Warum ohne "Const"?


Um nachzuweisen, daß das ganze Array (oder die ganze Scheibe (slice))
auf den Stack kopiert wird. Mit "const" würde ja nur einen Zeiger
übergeben (wie bei "var").

[...]

>> Erhoehe ich nun in der "markierten Zeile" die Anzahl der
uebergebenen
>> Elemente auf 10000 gibts beim naechsten Programmlauf einen
>> "Stack-Überlauf".
>
> Hast Du's auch mal ohne 'Slice()' (das erst ab D2
> vorhanden ist) versucht? Womöglich ist diese Funktion (für die
> ich selbst in den ASM-Dateien von D2 keinen Quell-Kode gefunden
> habe) für das 'Phänomen' verantwortlich? Vielleicht kopiert die
> ja den ausgewählten Bereich um, bevor sie ihn an die Ziel-Routine
> übergibt?

Slice ist sehr wahrscheinlich eine Pseudo-Funktion (wie Break oder
Continue), die Delphi nur signalisiert, was genau auf den Stack
kopiert werden soll. Delphi benutzt dafür dann wohl anonymen
inline-Code (ich meine damit: Delphi generiert an der Stelle etwas
Code, um die nötigen Sachen zu kopieren), so wie Delphi das bei
Writeln und Readln usw. macht.

Natürlich wird der ausgewählte Bereich auf den Stack kopiert. Das
versucht Felix ja gerade klarzumachen.

Ciao
--
Rudy Velthuis


Matthias Watermann

unread,
Feb 28, 1998, 3:00:00 AM2/28/98
to

rvelthuis schrieb am 28.02.98 in <34f7b...@news1.cityweb.de>:

> [...]
> >> {$MAXSTACKSIZE $00010000} // ich verkleinere den Stack mal etwas
> >>
> >> procedure TForm1.x(a: array of Integer);
> >
> > Warum ohne "Const"?
>
> Um nachzuweisen, daß das ganze Array (oder die ganze Scheibe (slice))
> auf den Stack kopiert wird. Mit "const" würde ja nur einen Zeiger
> übergeben (wie bei "var").

Wohl wahr. Aber: Warum sollte man absichtlich unnötigen Speicher
verbrauchen wollen? - Irgendwie hab' ich den Eindruck, daß ich
nicht mehr begreife, worum's hier überhaupt geht ;-)

> [...]


> Slice ist sehr wahrscheinlich eine Pseudo-Funktion (wie Break oder
> Continue), die Delphi nur signalisiert, was genau auf den Stack

Na ja, die beiden genannten Anweisungen sind (wie auch 'Exit') im
Grunde nur verkleidete 'GoTo'-Befehle (weil 'GoTo' selbst ja Bäbä
ist <g>).

> kopiert werden soll. Delphi benutzt dafür dann wohl anonymen
> inline-Code (ich meine damit: Delphi generiert an der Stelle etwas
> Code, um die nötigen Sachen zu kopieren), so wie Delphi das bei
> Writeln und Readln usw. macht.

'ReadLn' und 'Writeln' sind in TGPC.ASM kodiert.
Doch daß 'Slice()' ziemlich ,,pseudo'' ist, stimmt wohl :-)

> [...]


> Natürlich wird der ausgewählte Bereich auf den Stack kopiert. Das
> versucht Felix ja gerade klarzumachen.

Ahem ... Wenn Werte-Parameter (statt Referenzen) an eine
Routine übergeben werden, so werden die Daten doch =immer=
umkopiert, egal, um welchen Datentyp es sich handelt. Kannst Du
(oder jemand anderes) mir wohl mal erklären (gaanz langsam, zum
mitdenken), weshalb dieser simple (mit seit TP 2.01A bekannte)
Umstand plötzlich strittig sein soll? Danke.

Matthias Watermann

unread,
Feb 28, 1998, 3:00:00 AM2/28/98
to

rvelthuis schrieb am 27.02.98 in <34f73...@news1.cityweb.de>:

> [...]


> Wahrscheinlich jeder hat schon einmal ein Array in einer Schleife
> gefüllt, die eine Laufvariable vom Typ Integer hatte. Diese

Nur, wenn das Array auch für Integer "geeignet" ist, also Indizes
>256 und <=MaxInt enthalten kann.

> Integervariable wurde dann als Index benutzt. Das war in jeder Version
> von Pascal, die ich kenne (nicht nur auf Intel-Maschinen, auch auf
> Z80-, 6502- und 68000-Maschinen), möglich. Das ist wahrscheinlich
> sogar ISO-Pascal-Standard (da bin ich mir aber nicht ganz sicher).
> Einige Pascals haben nicht einmal eine ausschaltbare
> Bereichsüberprüfung. Also kann der Index wohl immer ein Integer sein,
> egal wie groß Integer ist, und wie groß das Array ist.

Wenn Du {a} ein "Array[Byte] of Irgendwas" hast, {b} den
Index mit einer Variablen >8Bit ansprichst (z.B. Word/Integer)
und {c} der Wert dieser Variablen >256 ist (so daß effektiv mind.
9 Bits verwendet werden), was wird dann realiter benutzt? MSB
oder LSB? Auf welchem Prozessor dies und auf welchem jenes?

Ich will damit sagen: Selbst, wenn es formal "erlaubt"
oder wenigstens praktisch "möglich" ist, einen "unpassenden"
Variablentyp zu benutzen, um auf ein Array-Element zuzugreifen,
sollte man es m.E. dennoch tunlichst vermeiden - jedenfalls, wenn
man die Funktionsweise seines Programmes nicht von der (womöglich
Versions-spezifischen) Datenausrichtung des Kompilers oder der
MSB/LSB-Anordnung des Prozessors abhängig machen will. Ich weiß
nicht, wie der Alpha-Proz seine Daten anordnet, aber
möglicherweise würde ein Programm, das unter WinNT (auf Intel)
scheinbar fehlerlos läuft, unter WinNT (auf Alpha) plötzlich
recht eigenwillige Ergebnisse zeitigen.

Rudy Velthuis

unread,
Mar 1, 1998, 3:00:00 AM3/1/98
to

Matthias Watermann schrieb in Nachricht

<6oiGB...@dfg.oln.ComLink.APC.org>...


>
> Ahem ... Wenn Werte-Parameter (statt Referenzen) an eine
> Routine übergeben werden, so werden die Daten doch =immer=
> umkopiert, egal, um welchen Datentyp es sich handelt. Kannst Du
> (oder jemand anderes) mir wohl mal erklären (gaanz langsam, zum
> mitdenken), weshalb dieser simple (mit seit TP 2.01A bekannte)
> Umstand plötzlich strittig sein soll? Danke.

Nee, brauche ich nicht. Das ist genau, was Felix hier demonstieren
wollte. Peter schrieb nämlich, das offene Arrays immer als call by
reference übergeben werden. Felix wollte nur zeigen, daß das so nicht
stimmt.

Matthias Watermann

unread,
Mar 1, 1998, 3:00:00 AM3/1/98
to

Rudy schrieb am 01.03.98 in <34f92...@news2.cityweb.de>:

> [...]


> wollte. Peter schrieb nämlich, das offene Arrays immer als call by
> reference übergeben werden. Felix wollte nur zeigen, daß das so nicht
> stimmt.

Möglicherweise meinte Peter ja ein "Array of Const", als er den
Terminus ,,Offene Arrays'' benutzte, wie hier:

Procedure Irgendwas(VieleWerte : Array of Const);
Begin
{ mach was mit 'VieleWerte' }
End;

Hier werden tatsächlich für alle Variablen-Typen im Array
mit VarSize >= SizeOf(LongInt) Zeiger übergeben (Details vgl.
Quell-Kode von System.Pas). Ein "Var" oder "Const" vor dem
Variablen-Namen hat dabei keine praktischen Auswirkungen. Selbst,
wenn da "Var VieleWerte ..." stünde, könnte man die übergebenen
Werte nicht verändern. Wie denn auch, wo doch bei einem solchen
Konstrukt nicht nur Variablen, sondern auch literale Werte
(Ziffern oder Zeichenketten) übergeben werden können:

{...}

Irgendwas(['toller Text', lokaleVar, True, globaleVar, 4711]);

{...}

Zur Erhöhung der Lesbarkeit würde ich ein "Const"
vor den Variablen-Namen schreiben, damit man gleich =sieht=, daß
man es hier (in praktischer Hinsicht jedenfalls) mit Konstanten
zu tun hat, während die o.a. Notation den (falschen) Eindruck
erwecken kann, es würden veränderbare Werte-Parameter übergeben.

Wilfried Kramer

unread,
Mar 2, 1998, 3:00:00 AM3/2/98
to

Hi,

Deine Ausführungen zur Berechnung/Verwendung von Indizes sind prima. Schließe mich voll an. Das wird in jedem Compiler so gemacht (und muß auch so sein).

>
> Ich sage nicht daß meine [0..0] Methode die *einzig* richtige ist. Du
> sagst aber das die [0..MaxIndex] Methode die einzig richtige ist. Das
> ist der Unterscheid zwischen uns. Deine favorite Methode funktioniert,
> meine aber auch. Ich hasse es nur für unfähig verkauft zu werden.
>

Deine Methode mit [0..0] hat für meinen Geschmack einen gravierenden Nachteil. Wohlgemerkt, der erzeugte Code ist absolut gleichwertig. Aber wenn ich Deine Methode verwende, muß ich im gesamten Modul die Bereichsprüfung abschalten. Also auch für die Zuweisung bei Subbereichstypen, die mit dem Array gar nichts zu tun haben.
Da nehme ich dann doch lieber [0..Maxindex] und erhalte einen Fehler, wenn ich auf eine Byte-Variable 786 zuweisen will.
Wie gesagt, nur mein persönlicher Geschmack.

Gruß
Wilfried


Christian Schroeder

unread,
Mar 2, 1998, 3:00:00 AM3/2/98
to
Matthias Watermann schrieb:

> > Slice ist sehr wahrscheinlich eine Pseudo-Funktion (wie Break oder
> > Continue), die Delphi nur signalisiert, was genau auf den Stack
>
> Na ja, die beiden genannten Anweisungen sind (wie auch 'Exit') im
> Grunde nur verkleidete 'GoTo'-Befehle (weil 'GoTo' selbst ja Bäbä
> ist <g>).

Hm, auch wenn das jetzt eher in den Thread "Ist 'GoTo' Bäbä?" gehoert:
Ich halte sowohl "break" als auch "exit" fuer absolut in Ordnung. Mir
wurde einmal beigebracht, dass ein Programm in erster Linie fuer
Menschen gemacht ist, dass also der Mensch den Quelltext moeglichst gut
verstehen soll. Der Compiler hat dann (gefaelligst) den richtigen Code
daraus zu erzeugen.
Und in diesem Sinne sind "break" oder "exit" sinnvoll, denn sie machen
ein Programm lesbarer. Ebenso wie die von Dir an anderer Stelle bereits
erwaehnten (kritisierten?) "try...except"-Bloecke. Fuer "goto" gilt
genau das jedoch nicht, denn mit "goto" kann ich bekanntlich meinen
Quelltext beliebig unverstaendlich gestalten.

Christian

vcard.vcf

Gunar Scholz

unread,
Mar 2, 1998, 3:00:00 AM3/2/98
to

Wilfried Kramer wrote:
>
> Deine Methode mit [0..0] hat für meinen Geschmack einen gravierenden
> Nachteil. Wohlgemerkt, der erzeugte Code ist absolut gleichwertig.
> Aber wenn ich Deine Methode verwende, muß ich im gesamten Modul die
> Bereichsprüfung abschalten.

Nein, das musst du nicht 'modulglobal' abschalten, du kannst das an den
entsprechenden Stellen mit {$R-} ausschalten und nachher mit {$R+}
wieder einschalten.

Felix

Gunar Scholz

unread,
Mar 2, 1998, 3:00:00 AM3/2/98
to

Matthias Watermann wrote:
>
> Möglicherweise meinte Peter ja ein "Array of Const", als er den
> Terminus ,,Offene Arrays'' benutzte, wie hier:

Das was er meint und das was er sagt stimmt leider bei ihm nicht immer
ueberein. Und da er das was er sagt nicht immer mit konkreten Beispielen
belegt, ist es manchmal schwer, ihn zu verstehen.

*

Es ging nicht darum, ob es sinnvoll ist die Parameter via 'var', 'const'
oder ohne zu uebergeben. Das muss jeder Programmierer fuer sein Projekt
selber entscheiden.
Den Rest hat Rudy ja schon beantwortet.

Felix


Rudy Velthuis

unread,
Mar 2, 1998, 3:00:00 AM3/2/98
to

Matthias Watermann schrieb in Nachricht

<6oiGC...@dfg.oln.ComLink.APC.org>...


>
>rvelthuis schrieb am 27.02.98 in <34f73...@news1.cityweb.de>:
>
>> [...]
>> Wahrscheinlich jeder hat schon einmal ein Array in einer Schleife
>> gefüllt, die eine Laufvariable vom Typ Integer hatte. Diese
>
> Nur, wenn das Array auch für Integer "geeignet" ist, also Indizes
> >256 und <=MaxInt enthalten kann.


Nee, darum geht es mir doch gerade. Ich kann ein array[0..100] ruhig
mit einem Integer indizieren, ohne das irgendetwas schiefgeht. Ich muß
natürlich dann sicher gehen, daß mein Index nicht < 0 oder > 100 wird.
Sonst ist die tatsächliche Größe (also 4 Byte für ein Integer) total
egal. Es geht um den Wert. Die beiden Typen (einerseits 0..100 -- ein
Subrange type, 1 byte groß -- und andererseits Integer -- ein 4 byte
großer Wert --) müssen nur Zuweisungskompatibel sein.

>> Integervariable wurde dann als Index benutzt. Das war in jeder
Version
>> von Pascal, die ich kenne (nicht nur auf Intel-Maschinen, auch auf
>> Z80-, 6502- und 68000-Maschinen), möglich. Das ist wahrscheinlich
>> sogar ISO-Pascal-Standard (da bin ich mir aber nicht ganz sicher).
>> Einige Pascals haben nicht einmal eine ausschaltbare
>> Bereichsüberprüfung. Also kann der Index wohl immer ein Integer
sein,
>> egal wie groß Integer ist, und wie groß das Array ist.

Ich meinte Code wie:

var


A: array[0..100] of Byte;

I: Integer;


begin
for I := 0 to 100 do

A[I] := Random(256);
Sortiere(A, 0, 100);


for I := 0 to 100 do

Writeln(A[I]);
{ usw. }
end;

Das lief bei mir immer. Etwas ähnliches (vermute ich nun einmal), hast
du in deiner Anfangszeit vielleicht auch schon einmal geschrieben (als
du noch nicht wußtest was Sizeof ist und noch nicht wußtest was genau
Zuweisungskompatibel und Unterbereich eigentlich sind). Und es lief!

>
> Wenn Du {a} ein "Array[Byte] of Irgendwas" hast, {b} den
> Index mit einer Variablen >8Bit ansprichst (z.B. Word/Integer)
> und {c} der Wert dieser Variablen >256 ist (so daß effektiv mind.
> 9 Bits verwendet werden), was wird dann realiter benutzt? MSB
> oder LSB? Auf welchem Prozessor dies und auf welchem jenes?

Wenn das Array nur [0..255] ist, greife ich mit einem Index > 256 über
die Grenzen des Arrays hinaus. Das ist natürlich immer ein Fehler.
Wenn aber das Array [0..200] ist, und ich mit einem Byte indiziere,
darf aber ich auch nicht über 200 hinausgehen, obwohl nichts
abgeschnitten wurde (Für 200 brauche ich ja auch in mindestens 8 Bit).

Es ging mir nicht um den Wert der Indexvariablen. Da gelten die
Grenzen des Arrays. Es ging um die *Größe* (Anzahl Bytes/Bits der
Indexvariablen).

Es wurde in diesem und dem anverwandten Thread ("Offene Arrays")
ständig behauptet, daß ich mit einem Integer kein Array [0..0]
indizieren kann, weil dann irgendetwas überschrieben wird. Du scheinst
das auch zu glauben (?). Also nochmal: Ich muß in
den Grenzen des Arrays bleiben. Ein Integer kann aber auch Werte
zwischen 0 und 255 enthalten und kann somit auch eine gültiger Index
sein für z.B. ein array[Byte] of Element. Wenn der Wert des Index aber
zu groß ist (also >= 256).

Es ging ja ursprünglich darum, daß ich mit einen Typ, der als (z.B.)
^array[0..0] of Element deklariert ist, nicht auf ein Array variabler
Größe (wie das von z.B. API-Funktionen zurückgegeben wird, oder wie
sie bei offenen Arrays nun einmal entstehen) zugreifen kann.

Ich habe behauptet, daß das doch möglich ist, wenn ich die
Bereichsüberprüfung abschalte. Peter Hellinger sagte (wie du?), daß
der Index dann ja nicht größer sein kann als ein Byte. Ich habe
behauptet,
daß das nicht notwendig ist, da der *Wert* des Index, und nicht die
*Größe* (in Bits/Bytes) entscheidend ist. Ich behaupte zusätzlich, daß
wenn mein Index
nicht über High(OffenesArray) hinausgeht, ich mit jedem Typ, der
*Zuweisungskompatibel* zu dem Index 0..0 ist (also Integer, ShortInt,
SmallInt, LongInt, Byte, Word und Cardinal), den Index bilden kann. Um
das zu machen, muß ich natürlich die automatische Bereichsüberprüfung
von
Delphi ausschalten, da mein Indexwert sehr wahrscheinlich über 0
hinausgehen wird. Ich (als Programmierer) bin dann natürlich selbst
dafür verantwortlich, daß mein Indexwert nicht über High(...)
hinausgeht (oder unter 0 geht). Das gleiche gilt für dynamisch
angelegte Arrays variabler Größe. Da darf ich natürlich auch nicht
über die Grenzen des tatsächlich allozierten Arrays hinausgehen.

Wenn das für den Zugriff deklarierte Array nun als array[0..MaxMemory
div SizeOf(Element)] definiert ist, ist es in etwa 2GB groß. Soviel
Speicher kann ich natürlich nie allozieren (und wenn doch, der
Durchschnittliche Benutzer kann es mit Sicherheit nicht). Ich muß also
bei einer solchen Deklaration den Index auch auf den tatsächlichen
Maximalwert überprüfen. Da ist die automatische Bereichsüberprüfung
(für diesen Zugriff) dann sowieso überflüssig.

Maßgeblich ist oben das Wort "Zuweisungskompatibel". Viele
Programmierer meinen immer noch, daß der Typ, womit indiziert wird,
kleiner oder gleich groß sein muß (mit "groß" meine ich die Anzahl
Byte/Bits
die ein Typ beansprucht) als der deklarierte Indextyp. Es geht aber
nicht um die
*Größe* des Index, sondern um den *Wert* des Index. Der wird von der
Bereichsüberprüfung ja auch getestet, und nicht die Größe. Die Hilfe
von Delphi sagt, daß die Typen Zuweisungskompatibel sein müssen. Und,
probier es aus, ich kann auch bei eingeschalteter autom.
Bereichsüberprüfung (Option $R+) einem Byte einen Integer zuweisen
(also A: Byte und B: Integer und trotzdem A := B), solange 0 <= Wert
des Integers <= 255. Also sind Byte und Integer
zuweisungskompatibel. Ich kann natürlich nicht (bei $R+) mit
einer Variable vom Typ Byte, die den *Wert* 101 enthält, ein
array[0..100] indizieren, obwohl 0..100 auch nur ein Byte groß ist.

>
> Ich will damit sagen: Selbst, wenn es formal "erlaubt"
> oder wenigstens praktisch "möglich" ist, einen "unpassenden"
> Variablentyp zu benutzen, um auf ein Array-Element zuzugreifen,
> sollte man es m.E. dennoch tunlichst vermeiden - jedenfalls, wenn
> man die Funktionsweise seines Programmes nicht von der (womöglich
> Versions-spezifischen) Datenausrichtung des Kompilers oder der
> MSB/LSB-Anordnung des Prozessors abhängig machen will. Ich weiß
> nicht, wie der Alpha-Proz seine Daten anordnet, aber
> möglicherweise würde ein Programm, das unter WinNT (auf Intel)
> scheinbar fehlerlos läuft, unter WinNT (auf Alpha) plötzlich
> recht eigenwillige Ergebnisse zeitigen.

Ob man es vermeiden soll, oder nicht, ist Ansichtssache. Der eine
findet das Definieren eines ausreichend großen (abstrakten) Arrays, um
auf die Daten zuzugreifen zu umständlich, und bedient sich halt des
[0..0]-Tricks. Der andere findet das nicht "robust" und portabel genug
und macht sich die Mühe.

Ich halte mich hier einfach an die Delphi-Hilfe. Delphi läuft ja im
Moment nur auf Wintel-Maschinen. Die Tricks werden meistens auch nur
für Wintel-APIs benutzt. Also ist das nicht so ein großes Thema
(imho). Portabilität ist eine schöne Sache, verträgt sich aber nicht
immer mit maschinennahe (oder betriebssystemnahe) Programmierung.
Code, der Windows-API-Routinen benutzt, ist im Grunde genommen schon
nicht mehr portabel.

Zweitens müssen wir ja schon mit Definitionen wie [0..0] arbeiten,
wenn wir nicht viele der API-Datenstrukturen in den Dateien in
[Delphi]\Source\RTL und -\VCL umschreiben wollen. Manchmal ist die
Obergrenze
auch von anderen Umständen abhängig, so daß nur der [0..0]-Trick in
allen Umständen paßt. Der Trick [0..0] kann übrigens in allen
Delphi-Versionen angwandt werden, ohne bedingte Kompilierung wie
"{$ifdef Win32} MaxMemory = $7FFFFFFF; {$else} MaxMemory = $FFF0;
{$endif}".

MfG

Rudy Velthuis

unread,
Mar 2, 1998, 3:00:00 AM3/2/98
to

Rudy Velthuis schrieb in Nachricht <34fb2...@news1.cityweb.de>...


>Es wurde in diesem und dem anverwandten Thread ("Offene Arrays")
>ständig behauptet, daß ich mit einem Integer kein Array [0..0]
>indizieren kann, weil dann irgendetwas überschrieben wird. Du
scheinst
>das auch zu glauben (?). Also nochmal: Ich muß in
>den Grenzen des Arrays bleiben. Ein Integer kann aber auch Werte
>zwischen 0 und 255 enthalten und kann somit auch eine gültiger Index
>sein für z.B. ein array[Byte] of Element. Wenn der Wert des Index
aber
>zu groß ist (also >= 256).

Korrektur des letzten Saztes. Der war nicht zu Ende:

"Wenn der Wert des Index aber zu groß ist (also >= 256), gibt es
natürlich eine Exception (bei $R+) oder der Wert wird nur
abgeschnitten auf ein Byte (bei $R-)".


Rudy

Rudy Velthuis

unread,
Mar 2, 1998, 3:00:00 AM3/2/98
to

>Wilfried Kramer schrieb in Nachricht
<01bd4571$719d5800$LocalHost@tiny-server>...


>Hi,
>
>Deine Ausführungen zur Berechnung/Verwendung von Indizes sind prima.
Schließe mich voll an. Das >wird in jedem Compiler so gemacht (und muß
auch so sein).
>
>>
>> Ich sage nicht daß meine [0..0] Methode die *einzig* richtige ist.
Du
>> sagst aber das die [0..MaxIndex] Methode die einzig richtige ist.
Das
>> ist der Unterscheid zwischen uns. Deine favorite Methode
funktioniert,
>> meine aber auch. Ich hasse es nur für unfähig verkauft zu werden.
>>

>Deine Methode mit [0..0] hat für meinen Geschmack einen gravierenden
Nachteil. Wohlgemerkt, der >erzeugte Code ist absolut gleichwertig.
Aber wenn ich Deine Methode verwende, muß ich im gesamten >Modul die

Bereichsprüfung abschalten. Also auch für die Zuweisung bei
Subbereichstypen, die mit >dem Array gar nichts zu tun haben.
>Da nehme ich dann doch lieber [0..Maxindex] und erhalte einen Fehler,

wenn ich auf eine Byte->Variable 786 zuweisen will.


>Wie gesagt, nur mein persönlicher Geschmack.

Ich kann die Bereichsüberprüfung ständig an- und ausschalten, wo und
wie oft ich das für nötig halte. Das gilt also nicht Modulweit,
sondern auch lokal. Ist natürlich auch etwas umständlich, und ich
selbst vermeide die [0..0] Methode auch wo ich kann. Sie ist aber
nicht grundsätzlich unmöglich oder gar falsch oder Pfusch. Und das
behauptet Peter. (Und *wie* er das behauptet!)

Florian Friesdorf

unread,
Mar 3, 1998, 3:00:00 AM3/3/98
to

Rudy Velthuis wrote:

> "Wenn der Wert des Index aber zu groß ist (also >= 256), gibt es
> natürlich eine Exception (bei $R+) oder der Wert wird nur
> abgeschnitten auf ein Byte (bei $R-)".

Das würde dann aber doch heißen, daß ich bei {$R-} mit der Definition
array[0..0] of Element nur die Elemente 0 bis 255 über array[Index]
ansprechen kann, da daß 256 Element wieder dem 0 entpsrechen würde.

Bye Flo

Peter Hellinger

unread,
Mar 3, 1998, 3:00:00 AM3/3/98
to

Rudy Velthuis schrieb in Nachricht <34fb3...@news1.cityweb.de>...


>Sie ist aber
>nicht grundsätzlich unmöglich oder gar falsch oder Pfusch. Und das
>behauptet Peter. (Und *wie* er das behauptet!)

Ich habe nicht einen schlüssigen Gegenbeweis gesehen.

Matthias Watermann

unread,
Mar 3, 1998, 3:00:00 AM3/3/98
to

Rudy schrieb am 02.03.98 in <34fb2...@news1.cityweb.de>:

> [...]


> > Nur, wenn das Array auch für Integer "geeignet" ist, also Indizes
> > >256 und <=MaxInt enthalten kann.
>
> Nee, darum geht es mir doch gerade. Ich kann ein array[0..100] ruhig
> mit einem Integer indizieren, ohne das irgendetwas schiefgeht. Ich muß

Das hängt wohl von der Definition von ,,schiefgehen'' ab ;-)

> natürlich dann sicher gehen, daß mein Index nicht < 0 oder > 100 wird.

Jau!

> [...]


> Es wurde in diesem und dem anverwandten Thread ("Offene Arrays")
> ständig behauptet, daß ich mit einem Integer kein Array [0..0]
> indizieren kann, weil dann irgendetwas überschrieben wird. Du scheinst
> das auch zu glauben (?).

Nein, ich wollte darauf hinweisen, daß es - strenggenommen
- =Zufall= ist, wenn und ob es funktioniert, denn es hängt {a}
davon ab, was der Kompiler bei der Umsetzung in ASM-Anweisungen
daraus macht (daher der Hinweis auf LSB/MSB) und {b} auf welchem
Prozessor das Programm läuft bzw. =welche= Register =wie= in
einem solchen Falle verwendet werden. Der Umstand alleine, daß es
mit bisherigen Borland-Kompilern auf Intel-Plattformen nicht zu
erkennbaren Problemen gekommen ist, heißt nicht, daß es generell
sinnvoll (und ungefährlich) ist, mit "unpassenden" Index-
Variablen auf Array-Elemente zugreifen zu wollen. Alldieweil es
doch überhaupt kein Problem ist, den Typ der verwendeten Index-
Variablen "passend" zum anzusprechenden Array zu deklarieren,
verstehe ich, offen gestanden, nicht recht, weshalb Du die
Benutzung "unpassender" Index-Variablen so erbittert verteidigst.

Das Problem mit dem ,,Überschreiben'' fremder
Speicherbereiche ist ein anderes, nur entfernt verwandtes. Dazu
hatte ich, glaube ich, ja schon irgendwann einmal bemerkt, daß
ich es für im wahren Sinne des Wortes schwach-sinnig halte,
leichtfertig auf entsprechende Prüfungen zu verzichten, sei es
die auch von Dir hervorgehobene eigene Prüfung des gültigen
Werte-Bereiches einer Index-Variablen, seien es die via
Kompiler-Schalter gebotenen Möglichkeiten.

> [...]


> Maßgeblich ist oben das Wort "Zuweisungskompatibel". Viele
> Programmierer meinen immer noch, daß der Typ, womit indiziert wird,
> kleiner oder gleich groß sein muß (mit "groß" meine ich die Anzahl
> Byte/Bits
> die ein Typ beansprucht) als der deklarierte Indextyp. Es geht aber
> nicht um die
> *Größe* des Index, sondern um den *Wert* des Index. Der wird von der
> Bereichsüberprüfung ja auch getestet, und nicht die Größe. Die Hilfe
> von Delphi sagt, daß die Typen Zuweisungskompatibel sein müssen. Und,
> probier es aus, ich kann auch bei eingeschalteter autom.
> Bereichsüberprüfung (Option $R+) einem Byte einen Integer zuweisen
> (also A: Byte und B: Integer und trotzdem A := B), solange 0 <= Wert
> des Integers <= 255. Also sind Byte und Integer
> zuweisungskompatibel. Ich kann natürlich nicht (bei $R+) mit
> einer Variable vom Typ Byte, die den *Wert* 101 enthält, ein
> array[0..100] indizieren, obwohl 0..100 auch nur ein Byte groß ist.

Was aber passiert mit den Bits realiter? Ich erinnere mich
an einen Reinfall, den ich vor ein paar Jahren erlebte. Ich
wollte sicherstellen, daß tatsächlich nur 8 Bits in eine
Byte-Variable geschrieben wurden und machte das ganz schlau:

ByteVar := Byte(IntegerVar AND $FF);

Das funktioniert auch entsprechend der o.a. Vorgabe. Allerdings
war das Ergebnis nicht ganz das, was ich mir erhofft hatte. Denn
=beabsichtigt= (aber in der Form eben =nicht= kodiert) war, daß
bei Werten>256 die "ByteVar" den Wert 256 zugewiesen bekommt; was
in diesem Falle aber z.B. bei "IntergerVar=257" ankam, war "0"
(Null). Eben weil das einzig gesetzte Bit das 8. war (wenn man
bei 0 anfängt zu zählen), während die Bits 0..7 alle nicht
gesetzt waren. Um den von mir gewünschten Effekt zu erhalten,
mußte ich die o.a. Formulierung also erweitern:

If (IntegerVar >= $FF) Then
ByteVar := $FF
Else ByteVar := Byte(IntegerVar AND $FF);

Was hat diese Reminisenz an eigene Gedankenlosigkeit mit
unserem Problem (IndexVariable & Array) zu tun? Nun, ich will
darauf hinweisen, daß wir uns nicht darauf verlassen sollten, daß
der Kompiler automatisch Kode erzeugt, der entweder meiner ersten
oder meiner zweiten Formulierung entspricht oder noch was ganz
anderes macht, sondern stattdessen diese Unwägbarkeiten
vermeiden, indem wir von vornherein "passende" Variablen-Typen
wählen. Die von Dir ins Spiel gebrachte ,,Zuweisungs-
Kompatibilität'' ist daher auch keine Lösung, sondern das
Problem! Denn was passiert bei der Zuweisung eines Integerwertes
an eine Byte-Variable? Und: Entspricht dies dem, was ich
tatsächlich beabsichtige und wünsche?

> [...]


> > Ich will damit sagen: Selbst, wenn es formal "erlaubt"
> > oder wenigstens praktisch "möglich" ist, einen "unpassenden"
> > Variablentyp zu benutzen, um auf ein Array-Element zuzugreifen,
> > sollte man es m.E. dennoch tunlichst vermeiden - jedenfalls, wenn
> > man die Funktionsweise seines Programmes nicht von der (womöglich
> > Versions-spezifischen) Datenausrichtung des Kompilers oder der
> > MSB/LSB-Anordnung des Prozessors abhängig machen will. Ich weiß
> > nicht, wie der Alpha-Proz seine Daten anordnet, aber
> > möglicherweise würde ein Programm, das unter WinNT (auf Intel)
> > scheinbar fehlerlos läuft, unter WinNT (auf Alpha) plötzlich
> > recht eigenwillige Ergebnisse zeitigen.
>
> Ob man es vermeiden soll, oder nicht, ist Ansichtssache. Der eine

Hmm, ich persönlich halte Portabilität (immer in den
Grenzen des zugrundeliegenden BS') für eine - nennen wir's: -
Selbstverständlichkeit, nicht ,,Ansichtssache''. Schließlich
drückt sich das ja letzten Endes auch in Mark und Pfennig (oder
möglicherweise bald in Ecu und Cent) aus ;-)

Matthias Watermann

unread,
Mar 3, 1998, 3:00:00 AM3/3/98
to

chschroe schrieb am 02.03.98 in <34FA9690...@math.uni-goettingen.de>:

> [...]


> > > Slice ist sehr wahrscheinlich eine Pseudo-Funktion (wie Break oder
> > > Continue), die Delphi nur signalisiert, was genau auf den Stack
> >
> > Na ja, die beiden genannten Anweisungen sind (wie auch 'Exit') im

> > Grunde nur verkleidete 'GoTo'-Befehle (weil 'GoTo' selbst ja B=E4b=E4
> > ist <g>).
>
> Hm, auch wenn das jetzt eher in den Thread "Ist 'GoTo' B=E4b=E4?" gehoert=


> :
> Ich halte sowohl "break" als auch "exit" fuer absolut in Ordnung. Mir

Ich auch.

> [...]


> Und in diesem Sinne sind "break" oder "exit" sinnvoll, denn sie machen
> ein Programm lesbarer.

Darüber könnte man durchaus streiten ;-)

> Ebenso wie die von Dir an anderer Stelle bereits
> erwaehnten (kritisierten?) "try...except"-Bloecke. Fuer "goto" gilt
> genau das jedoch nicht, denn mit "goto" kann ich bekanntlich meinen
> Quelltext beliebig unverstaendlich gestalten.

Sicher, Du ,,kannst'', aber Du mußt nicht!

>------------------------------- schnipp -------------------------------------
Begin
While Bedingung1 Do Begin

{ mach was }

If bedingung2 Then
Break;

{ mach noch mehr }

If Bedingung3 Then
Continue;

{ mach noch mehr }

If Bedingung4 Then
Exit;

{ mach den Rest }
End;

{ letzte Arbeiten }

End;
>------------------------------- schnapp -------------------------------------

Ist das Gleiche wie:

>------------------------------- schnipp -------------------------------------
Begin
While Bedingung1 Do Begin
ContLabel:

{ mach was }

If bedingung2 Then
Goto BreakLabel;

{ mach noch mehr }

If Bedingung3 Then
Goto ContLabel;

{ mach noch mehr }

If Bedingung4 Then
Goto ExitLabel;

{ mach den Rest }
End;
BreakLabel:

{ letzte Arbeiten }

ExitLabel:
End;
>------------------------------- schnapp -------------------------------------

Ich persönlich halte die zweite Variante für =lesbarer=,
weil man sofort =sieht=, wohin gesprungen wird, während man bei
der ersten =wissen= muß, wie Continue/Break/Exit arbeiten, um den
Kode verstehen zu können. Da ich es aber weiß, verwende ich
i.d.R. Konstrukte wie das erste, doch ich habe auch keine
Skrupel, da, wo es sinnvoll ist, auch GoTos einzusetzen.

Rudy Velthuis

unread,
Mar 3, 1998, 3:00:00 AM3/3/98
to

Peter Hellinger schrieb in Nachricht <6dfp5u$k5f$2...@news.nacamar.de>...


Ich habe auch keinen schlüssigen Beweis gesehen (weder von dir, noch
von anderen), daß die Methode [0..0] falsch ist.

Rudy

Rudy Velthuis

unread,
Mar 3, 1998, 3:00:00 AM3/3/98
to

Florian Friesdorf schrieb in Nachricht
<34fb5242...@news.uni-ulm.de>...

Nein, da habe ich wohl etwas zu hastig korrigiert.

Ich kann mit $R- auch über 255 hinaus indizieren. Da das Array[Byte]
aber in
Wirklichkeit nur 256 Elemente hat, gehe ich dann über die Grenzen
hinaus:
Ich lese oder schreibe den Speicher "hinter" dem Array. Das *kann*
böse Folgen haben.

Die [0..0] Methode wird aber (von mir) nur für Arrays variabler Größe
angewandt. Ich lege damit also im Grunde genommen nur fest, daß ich
auf ein Array zugreifen möchte, daß den Anfang bei MyArray[0] hat und
Elemente vom Typ Etwas enthält. Die tatsächliche Größe ist mir bei der
Deklaration noch nicht bekannt. (Eindimensionale) Arrays haben ja per
Definition alle Datenelemente hintereinander im Speicher liegen. Nur
die *Anzahl* Elemente wird erst zur Laufzeit bekannt.

Diese Methode wird (von mir) entweder für offene Arrays verwendet,
oder für Allokationen von Arrays, z.B. ein Array of TPoint für eine
Polygon-Routine oder ähnliches.

Ich kann sogar (bei $R-) auf das das 10000. Element zugreifen, so das
dann im
allozierten Speicher liegt. Nur wird immer wieder behauptet, ich könne
bei Indizes, die (hier) mehr als 8 bit beanspruchen, irgendetwas im
Speicher überschreiben (nämlich die Indexvariable).

Der für den Zugriff benötigte Index (also was dann zwischen den
eckigen Klammern kommt) ist ein Ausdruck, der Zuweisungskompatibel
sein muß zu dem Typ des deklarierten Index (also zum Typ 0..0. 0..0
ist wirklich ein Typ, ich kann eine Variable von diesem Typ
deklarieren). Der Index ist also keine (irgendwo versteckte) Variable,
die überschrieben werden kann, sondern wirklich nur ein Wert, der auf
den Zeiger zum Anfang des Arrays addiert wird, um die richtige
Speicherstelle zu berechnen.

Das sagt auch die Online-Hilfe unter dem Stichwort "Indexes" (oder
"Indizes" oder so, ich benutze das englische Delphi).

Und diese Tatsache können oder wollen einige (vor allem einer) in
diesem Thread (und in dem anverwandten Thread "Offene Arrays") nicht
wahrhaben.

Auch darf ich natürlich nicht über die Grenzen des tatsächlichen
Arrays hinausgehen. Dafür muß ich also überprüfen, ob der benutzte
Index nicht zu hoch ist (oder sogar zu niedrig). Da ich das sowieso
muß, kann ich also für diesen einen Zugriff getrost auf die
*automatische* Bereichsüberprüfung des Index verzichten. Das muß ich
sogar, um meinen [0..0]-Trick anzuwenden. Das muß aber genausogut
derjenige, der die andere Methode (also Deklaration mit
array[0..BerechneterMaximumIndex]) anwendet. Er kann sich nämlich auch
nicht auf seine Bereichsprüfung verlassen, da die nur auf
BerechneterMaximumIndex prüft und nicht auf den wirklichen Höchstwert
des tatsächlichen Arrayindex (also bei offenen Arrays den
High()-Wert).

Also meine Korrektur war zu voreilig und sogar falsch. Entschuldige.

Peter Hellinger

unread,
Mar 4, 1998, 3:00:00 AM3/4/98
to

Matthias Watermann schrieb in Nachricht

<6p9$b-J...@dfg.oln.ComLink.APC.org>...


> Was hat diese Reminisenz an eigene Gedankenlosigkeit mit
> unserem Problem (IndexVariable & Array) zu tun? Nun, ich will
> darauf hinweisen, daß wir uns nicht darauf verlassen sollten, daß
> der Kompiler automatisch Kode erzeugt, der entweder meiner ersten
> oder meiner zweiten Formulierung entspricht oder noch was ganz
> anderes macht, sondern stattdessen diese Unwägbarkeiten
> vermeiden, indem wir von vornherein "passende" Variablen-Typen
> wählen. Die von Dir ins Spiel gebrachte ,,Zuweisungs-
> Kompatibilität'' ist daher auch keine Lösung, sondern das
> Problem! Denn was passiert bei der Zuweisung eines Integerwertes
> an eine Byte-Variable? Und: Entspricht dies dem, was ich
> tatsächlich beabsichtige und wünsche?


For i:= 0 to MaxInt DO WriteLn ('!!!'); // 8-)

Helli

Wilfried Kramer

unread,
Mar 4, 1998, 3:00:00 AM3/4/98
to

>> Aber wenn ich Deine Methode verwende, muß ich im gesamten Modul die
>> Bereichsprüfung abschalten.
>
>Nein, das musst du nicht 'modulglobal' abschalten, du kannst das an den
>entsprechenden Stellen mit {$R-} ausschalten und nachher mit {$R+}
>wieder einschalten.
>
>Felix
>
OK, stimmt. Aber willst Du wirklich jede Array-Operation mit {$R-} und
{$R+} einrahmen? Das ist mir eigentlich viel zu mühsam.

Wilfried


Matthias Watermann

unread,
Mar 4, 1998, 3:00:00 AM3/4/98
to

Ich auch.

{ mach was }

If bedingung2 Then
Break;

{ mach noch mehr }

If Bedingung3 Then
Continue;

{ mach noch mehr }

If Bedingung4 Then
Exit;

{ mach den Rest }
End;

{ letzte Arbeiten }

End;
>------------------------------- schnapp -------------------------------------

Ist das Gleiche wie:

{ mach was }

If bedingung2 Then
Goto BreakLabel;

{ mach noch mehr }

If Bedingung3 Then
Goto ContLabel;

{ mach noch mehr }

If Bedingung4 Then
Goto ExitLabel;

{ mach den Rest }

ContLabel:

Florian Friesdorf

unread,
Mar 4, 1998, 3:00:00 AM3/4/98
to

Rudy Velthuis wrote:

> allozierten Speicher liegt. Nur wird immer wieder behauptet, ich könne
> bei Indizes, die (hier) mehr als 8 bit beanspruchen, irgendetwas im
> Speicher überschreiben (nämlich die Indexvariable).
>
> Der für den Zugriff benötigte Index (also was dann zwischen den
> eckigen Klammern kommt) ist ein Ausdruck, der Zuweisungskompatibel
> sein muß zu dem Typ des deklarierten Index (also zum Typ 0..0. 0..0
> ist wirklich ein Typ, ich kann eine Variable von diesem Typ
> deklarieren). Der Index ist also keine (irgendwo versteckte) Variable,
> die überschrieben werden kann, sondern wirklich nur ein Wert, der auf
> den Zeiger zum Anfang des Arrays addiert wird, um die richtige
> Speicherstelle zu berechnen.

Sehe ich auch so.

> Das sagt auch die Online-Hilfe unter dem Stichwort "Indexes" (oder
> "Indizes" oder so, ich benutze das englische Delphi).
>
> Und diese Tatsache können oder wollen einige (vor allem einer) in
> diesem Thread (und in dem anverwandten Thread "Offene Arrays") nicht
> wahrhaben.

Ich muß jetzt einfach mal meinen Eindruck von dieser Diskussion
loswerden.

Ich denke die von dir erwähnten "einigen" sehen das Problem nicht bei
der momentanen Delphi-Version. Sie stellen aber an seinen Code den
Anspruch auch unter anderen Pascal-Compilern auf anderen Plattformen
zu funktionieren.
Es gibt wohl oder könnte vielleicht einmal andere Pascal-Compiler
geben, die die Array-Indizierung nicht mit reiner Zeigerarithmetik
machen, bzw. evtl. für Byte-Indizes 8bit Register verwenden.

Nun gut, wenn jemand diesen Anspruch hat, soll er ihn haben.
Allerdings sollte er dann nicht den Anspruch haben den Rest der Welt
davon überzeugen zu wollen und andere Ansichten als Unfug bezeichnen.

1. In den Delphi-Manuals steht, daß wie du oben beschreibst der für
den Zugriff benötigte Index zuweisungskompatibel zu dem Typ des
deklarierten Index sein muß und
2. Borland verwendet in der VCL ebenfalls Indizes vom Typ Integer zum
indizieren von z.B array[0..8191] of TIrgendwas.

SizeOf(Integer) ist in ObjectPascal nicht immer gleich groß.
So war sie in Delphi1 2 Byte, in Delphi 2&3 sind es 4 Byte.

Imho hab ich somit die Garantie, daß ich auch in zukünftigen Versionen
von Delphi und höchstwahrscheinlich auch den meisten anderen
Pascal-Compilern einen array[Byte] mit einem
Index: Byte/ShortInt/Integer/Cardinal adressieren kann, ohne bei {R-}
irgendetwas zu überschreiben.

Bye Flo

Rudy Velthuis

unread,
Mar 4, 1998, 3:00:00 AM3/4/98
to

Wilfried Kramer schrieb in Nachricht

<34fcac2a...@news.online.de>...


Ist es nicht mühsam, [0..MaxMemory div SizeOf(Irgendetwas) - 1] zu
definieren? Ist wohl Ansichtssache.

Rudy Velthuis

unread,
Mar 5, 1998, 3:00:00 AM3/5/98
to

Matthias Watermann schrieb in Nachricht

<6p9$b-J...@dfg.oln.ComLink.APC.org>...


>
>Rudy schrieb am 02.03.98 in <34fb2...@news1.cityweb.de>:
>
>> [...]
>> > Nur, wenn das Array auch für Integer "geeignet" ist, also Indizes
>> > >256 und <=MaxInt enthalten kann.
>>
>> Nee, darum geht es mir doch gerade. Ich kann ein array[0..100]
ruhig
>> mit einem Integer indizieren, ohne das irgendetwas schiefgeht. Ich
muß
>
> Das hängt wohl von der Definition von ,,schiefgehen'' ab ;-)
>
>> natürlich dann sicher gehen, daß mein Index nicht < 0 oder > 100
wird.
>
> Jau!
>
>> [...]
>> Es wurde in diesem und dem anverwandten Thread ("Offene Arrays")
>> ständig behauptet, daß ich mit einem Integer kein Array [0..0]
>> indizieren kann, weil dann irgendetwas überschrieben wird. Du
scheinst
>> das auch zu glauben (?).


> Nein, ich wollte darauf hinweisen, daß es - strenggenommen
> - =Zufall= ist, wenn und ob es funktioniert, denn es hängt {a}
> davon ab, was der Kompiler bei der Umsetzung in ASM-Anweisungen
> daraus macht (daher der Hinweis auf LSB/MSB)

Nein, das stimmt eben nicht. In allen mir bekannten Compilern (o.a. C,
C++ und Pascal auf mehreren Machinen) wird ein array-index so
berechnet:

@MeinArray[MeinIndex] = @MeinArray[0] + MeinIndex *
SizeOf(ElementTyp)

Dieser Zeiger wird dann für den Zugriff benutzt.

und {b} auf welchem
> Prozessor das Programm läuft bzw. =welche= Register =wie= in
> einem solchen Falle verwendet werden. Der Umstand alleine, daß es
> mit bisherigen Borland-Kompilern auf Intel-Plattformen nicht zu
> erkennbaren Problemen gekommen ist, heißt nicht, daß es generell
> sinnvoll (und ungefährlich) ist, mit "unpassenden" Index-
> Variablen auf Array-Elemente zugreifen zu wollen. Alldieweil es
> doch überhaupt kein Problem ist, den Typ der verwendeten Index-
> Variablen "passend" zum anzusprechenden Array zu deklarieren,
> verstehe ich, offen gestanden, nicht recht, weshalb Du die
> Benutzung "unpassender" Index-Variablen so erbittert verteidigst.


Ich verteidige sie nicht. Ich verwende sie nicht einmal sehr häufig.
Ich finde aber, daß es nicht *falsch* ist, eine solche Definition zu
benutzen, erst recht nicht in Delphi. Peter Hellinger behauptet aber,
das sei Pfusch und total falsch. Das kam mir in den falschen Hals.

Es gibt ja übrigens nur Delphi for Windows auf Wintel-Maschinen. Bis
sich das ändert, hat sich Delphi bestimmt schon wieder geändert (D4,
D5 etc.). Dann sehe ich schon weiter (hab' bis dahin wohl viel Zeit).


Du möchtest eine Art "Clipping"-Funktion. Die gibt es afaik in keinem
Compiler.

> ...darauf hinweisen, daß wir uns nicht darauf verlassen sollten, daß


> der Kompiler automatisch Kode erzeugt, der entweder meiner ersten
> oder meiner zweiten Formulierung entspricht oder noch was ganz
> anderes macht, sondern stattdessen diese Unwägbarkeiten
> vermeiden, indem wir von vornherein "passende" Variablen-Typen
> wählen.

Ich kann mich aber auch nicht immer auf die automatischen Prüfungen
von Delphi verlassen. Also wiegen mich doch die ganzen Prüfungen
manchmal in Sicherheit, wo keine ist. Eigenverantwortlichkeit ist eben
Pflicht, auch bei einer ziemlich "geschützten" Sprache wie Object
Pascal. Du erwähntest in einem anderen Thread, daß du am liebsten die
PChar Parameter (in Eigenregie) simulierst mit PChar(@S[1]) o.ä. Da
lassen dich dann eben wieder alle eingebauten Prüfungen im Stich.
Diese Situationen gibt es immer wieder. In anderen Sprachen, die schon
Jahrzehnten benutzt werden, wie z.B. C oder auch C++ (oder gar
Assembler), gibt es viel weniger Prüfungen. Trotzdem werden immer noch
ganze Betriebssysteme (Linux in C oder C++?) in dieser Sprache
geschrieben.

Imho sollte es jedem selbst überlassen sein, wie sicher er sich fühlt
und welche Prüfungen er einschaltet. Ich werde niemand verdammen oder
Pfuscher nennen (tust du auch nicht, weiß ich :-), weil er anderer
Meinung ist in dieser Sache.

>> Ob man es vermeiden soll, oder nicht, ist Ansichtssache. Der eine
>
> Hmm, ich persönlich halte Portabilität (immer in den
> Grenzen des zugrundeliegenden BS') für eine - nennen wir's: -
> Selbstverständlichkeit, nicht ,,Ansichtssache''. Schließlich
> drückt sich das ja letzten Endes auch in Mark und Pfennig (oder
> möglicherweise bald in Ecu und Cent) aus ;-)


Portabilität ist m.E. für Delphi zwar nicht so ganz wichtig, da es ja
Delphi im Moment (und mit Sicherheit auch in der näheren Zukunft) nur
für Wintel gibt. Auch auf dem Alpha nur unter Wintel-Emulatoren.

Portabilität ist eben nicht immer eine absolute Größe, da gibt es
Gradierungen. Sogar Win16 und Win32 sind ziemlich verschieden, also
kann ich im Rahmen von Wintel nicht einmal portabel bleiben. Das gilt
natürlich nicht für allgemeinere Routinen, ohne API-Aufrufe. Da hast
du Recht. Nur: vollständige Portabilität ist sowieso im Moment nicht
möglich. Also ist der Grad der Abweichung imho wieder Ansichtssache.
Es geht eben darum, was ich vertreten kann, ggü mir, meinem Nachfolger
oder (wenn es den gibt) meinen Arbeit- oder Auftraggeber. Um so
weniger portabel ich bin, um so mehr muß ich (oder irgendwer)
irgendwann umschreiben. Das ist lästig, aber da geht's dann drum, was
noch vertretbar/zumutbar ist. Wichtiger ist, das Schnittstellen und
Wirkungsweise kompatibel zu vorigen Versionen bleiben. Intern kann
sich da einiges geändert haben. Alles muß natürlich *möglichst*
fehlerfrei sein (möglichst, denn gegen Denkfehler ist keiner gefeit).

Rudy Velthuis

unread,
Mar 5, 1998, 3:00:00 AM3/5/98
to

Peter Hellinger schrieb in Nachricht <6di7t0$m41$4...@news.nacamar.de>...


>
>Matthias Watermann schrieb in Nachricht

>> Die von Dir ins Spiel gebrachte ,,Zuweisungs-
>> Kompatibilität'' ist daher auch keine Lösung, sondern das
>> Problem! Denn was passiert bei der Zuweisung eines Integerwertes
>> an eine Byte-Variable? Und: Entspricht dies dem, was ich
>> tatsächlich beabsichtige und wünsche?
>
>

>For i:= 0 to MaxInt DO WriteLn ('!!!'); // 8-)


Hoffentlich war dein I kein Byte ;)

Peter Hellinger

unread,
Mar 5, 1998, 3:00:00 AM3/5/98
to

Rudy Velthuis schrieb in Nachricht <34fdd...@news2.cityweb.de>...

>Ist es nicht mühsam, [0..MaxMemory div SizeOf(Irgendetwas) - 1] zu
>definieren? Ist wohl Ansichtssache.

Einmal bei der Deklaration gegen hundertmal im Code? Rein von der
Tipparbeit schon die bessere Methode, von dem anderen Kram gar
nicht zu reden...

Helli

Florian Friesdorf

unread,
Mar 5, 1998, 3:00:00 AM3/5/98
to

Florian Friesdorf wrote:

> Ich denke die von dir erwähnten "einigen" sehen das Problem nicht bei
> der momentanen Delphi-Version. Sie stellen aber an seinen Code den

muß natürlich ihren Code heissen.

Bye Flo


Rudy Velthuis

unread,
Mar 5, 1998, 3:00:00 AM3/5/98
to

Rudy Velthuis schrieb in Nachricht <34fde...@news2.cityweb.de>...


>
>Du möchtest eine Art "Clipping"-Funktion. Die gibt es afaik in keinem
>Compiler.
>

Bevor da wieder Mißverständnisse auftauchen, Ich meine:

Die gibt es vielleicht als Funktion in einer Sprache, aber nicht als
automatisches Compiler-Feature, wie Bereichsüberprüfung oder
Stackprüfung oder so.

Rudy

Gunar Scholz

unread,
Mar 6, 1998, 3:00:00 AM3/6/98
to

Wilfried Kramer wrote:
> Aber willst Du wirklich jede Array-Operation mit {$R-} und
> {$R+} einrahmen? Das ist mir eigentlich viel zu mühsam.

Nun, IO-Operationen mit {$I-} und {$I+} einzurahmen (und danach IOResult
abzufragen), Programmteile mit try..except bzw. try..finally
einzurahmen, Rueckgabewerte von Funktionen auszuwerten, ... ist muehsam.
Muehsam ernaehrt sich das Eichhoernchen....

Felix

Gunar Scholz

unread,
Mar 6, 1998, 3:00:00 AM3/6/98
to

Rudy Velthuis wrote:
>
> Ich habe auch keinen schlüssigen Beweis gesehen (weder von dir, noch
> von anderen), daß die Methode [0..0] falsch ist.

Nun, da die [0..0]-Gegner keinen Beweis liefern, was da mit dem Index
schieflaufen soll, versuche ich zu zeigen, dass sie diesen Beweis nicht
bringen koennen.
Ich spreche hierbei nur von Delphi (gemaess dem Namen dieser Newsgroup)
und Borland Pascal (da das hier auch nicht wesentlich anders ist als in
16-bit-Delphi).

Hier ein paar Codefragmente auf die ich mich beziehe:

var
a: array [min..max] of Daten;

a[x] := Irgendwas_vom_Typ_Daten;

Der Einfachkeit halber deklariere ich mein Array global und statisch.
(Das "offener Arrays" meistens anders verwendet werden, duerfte
inzwischen jedem klar sein. Fuer die (angebliche) Index-Ueberschreitung
spielt es keine Rolle, wo das Array angelegt wird.)

Ich habe Peter Hellinger's Argumentation so verstanden:
Er ist der Meinung, dass ich mit einem Zugriff auf ein Element 'x', bei
dem 'x' groesser als 255 ist, z.B. 260, eines Arrays mit 'max' = 255,
irgendetwas ueberschrieben wird, da fuer diesen Index ein Byte
ausreicht, und '260' dann einen Ueberlauf erzeugt.
Ich mag ihn da auch falsch verstanden haben, dann bitte ich um
Korrektur.
Falls nicht, sage ich dazu folgendes:

Es ist nicht definiert wieviel Byte fuer den Index verwendet werden.

Was braucht das Programm um auf den Inhalt von a[x] zugreifen zu
koennen?
Es benoetigt die Speicher-Adresse an der das Element 'x' steht.
Wie erhaelt das Programm diese Adresse?
Indem es 'x' (minus min, wenn min > 0) mit SizeOf(Daten) multipliziert
und zur Basisadresse von 'a' addiert. (Manchmal erzeugt der Compiler
auch Code, der nicht haargenauso rechnet, dafuer aber "optimierter" ist.
Das Ergebnis bleibt jedoch gleich).
In 32-bit-Programmen wird eine 32bit-Adresse errechnet, in
16-bit-Programmen ein 16bit-Offset. An dieser Adresse ist dann das
Element 'x' zu finden. Delphi und BP rechnen dabei stets in 32- bzw.
16-bit-Registern, egal ob max nun 255 oder 65535 oder sonstwas ist.

Ich kann auch kein Array deklarieren, bei dem (max-min)*SizeOf(Daten)
die 2GB bzw. 64k-Grenze ueberschreiten. Ebenso kann ich fuer ein Array
maximal soviel Speicher anfordern, dass ich darin ((2GB bzw. 64k) div
SizeOf(Daten) - 1) Elemente speichern kann. Und da ich in jedem Fall
selbst ueberwachen muss, dass ich nicht auf Elemente ausserhalb des
angeforderten Speicher-Bereiches zugreife, errechnet das Programm auch
keine Adresse, die nicht mit 32 bzw. 16 Bit dargestellt werden kann.

Es ist also unter Delphi und Borland Pascal nicht relevant, wieviel
Bytes (oder Bits) zur Darstellung von 'max' (oder 'max' - 'min')
benoetigt werden.

Soweit meine "Behauptung". Ich bitte um Beweise, die eindeutig dagegen
sprechen. In dem Fall werde ich nie wieder behaupten, dass ein
[0..0]-Array einem genauso "bedenkenlos" eingesetzt werden kann wie ein
[0..max]-Array. (Die Formulierung "genauso bedenkenlos" beinhaltet
logischerweise nicht die "Gedanken", die man sich in beiden Faellen
sowieso machen muss.)

Felix


Peter Hellinger

unread,
Mar 7, 1998, 3:00:00 AM3/7/98
to

Gunar Scholz schrieb in Nachricht <350074F4...@pride.de>...

>Ich habe Peter Hellinger's Argumentation so verstanden:


Ich sagte nicht "es wird", ich sagte "es kann". Und daß es syntaktisch nicht
korrekt ist, steht doch ausser ejder Frage oder?

Helli


Rudy Velthuis

unread,
Mar 7, 1998, 3:00:00 AM3/7/98
to

Gunar Scholz schrieb in Nachricht <350074F4...@pride.de>...

>Rudy Velthuis wrote:
>>
>> Ich habe auch keinen schlüssigen Beweis gesehen (weder von dir,
noch
>> von anderen), daß die Methode [0..0] falsch ist.
>
>Nun, da die [0..0]-Gegner keinen Beweis liefern, was da mit dem Index
>schieflaufen soll, versuche ich zu zeigen, dass sie diesen Beweis
nicht
>bringen koennen.
>Ich spreche hierbei nur von Delphi (gemaess dem Namen dieser
Newsgroup)
>und Borland Pascal (da das hier auch nicht wesentlich anders ist als
in
>16-bit-Delphi).

[... Siehe Originalmail ...]

>Soweit meine "Behauptung". Ich bitte um Beweise, die eindeutig
dagegen
>sprechen. In dem Fall werde ich nie wieder behaupten, dass ein
>[0..0]-Array einem genauso "bedenkenlos" eingesetzt werden kann wie
ein
>[0..max]-Array. (Die Formulierung "genauso bedenkenlos" beinhaltet
>logischerweise nicht die "Gedanken", die man sich in beiden Faellen
>sowieso machen muss.)

Felix, ich sehe es genau so. Ich danke dir für deine (erneute)
Erklärung. Ich befürchte nur, daß die (der) [0..0]-Gegner einfach
nicht zu überzeugen sind (ist).

Mit freundlichen Grüßen

Gunar Scholz

unread,
Mar 9, 1998, 3:00:00 AM3/9/98
to

Rudy Velthuis wrote:
>
> Felix, ich sehe es genau so. Ich danke dir für deine (erneute)
> Erklärung. Ich befürchte nur, daß die (der) [0..0]-Gegner einfach
> nicht zu überzeugen sind (ist).

Es war nicht meine primaer Absicht mit diesem Posting die [0..0]-Gegner
zu ueberzeugen. Ich wollte sie herausfordern, mir endlich klar zu
zeigen, was da Negatives passieren soll. Offensichtlich koennen sie das
aber nicht...

Felix

Gunar Scholz

unread,
Mar 9, 1998, 3:00:00 AM3/9/98
to

Peter Hellinger wrote:
>
> Gunar Scholz schrieb in Nachricht <350074F4...@pride.de>...
> >Ich habe Peter Hellinger's Argumentation so verstanden:
>
> Ich sagte nicht "es wird", ich sagte "es kann".

Aber was da ueberschrieben werden "kann" hast du immer noch nicht
gesagt.

> Und daß es syntaktisch nicht
> korrekt ist, steht doch ausser ejder Frage oder?

Was ist denn hier syntaktisch nicht korrekt?

var
a: array [0..3] of IrgendwasTyp;
begin
a[5] := Irgendwas;
end;

Felix

Peter Hellinger

unread,
Mar 9, 1998, 3:00:00 AM3/9/98
to

Gunar Scholz schrieb in Nachricht <35039895...@pride.de>...

>Es war nicht meine primaer Absicht mit diesem Posting die [0..0]-Gegner
>zu ueberzeugen. Ich wollte sie herausfordern, mir endlich klar zu
>zeigen, was da Negatives passieren soll. Offensichtlich koennen sie das
>aber nicht...


Ich habe es 6 x (in Worten: Sechs) dargelegt. Wie oft soll ich es deiner
Meinung nach noch darlegen?

Daß es auf einem konkreten Rechner mit konkretem Compiler und konkretem
Programm _scheinbar_ kein Fehler auftritt, ist doch kein Beweis für die
Fehlerfreiheit der Routine! Umsonst würde der Compiler ja nicht meckern,
oder?

Helli


Peter Hellinger

unread,
Mar 9, 1998, 3:00:00 AM3/9/98
to

Gunar Scholz schrieb in Nachricht <3503AD12...@pride.de>...

>Was ist denn hier syntaktisch nicht korrekt?
>
>var
> a: array [0..3] of IrgendwasTyp;
>begin
> a[5] := Irgendwas;
>end;

Schalt den Rangecheck ein, und du wirst sehen, daß der Compiler es nicht
übersetzt. Eindeutig genug?

Helli

Rudy Velthuis

unread,
Mar 9, 1998, 3:00:00 AM3/9/98
to

Gunar Scholz schrieb in Nachricht <3503AD12...@pride.de>...
>

>> Und daß es syntaktisch nicht
>> korrekt ist, steht doch ausser ejder Frage oder?
>

>Was ist denn hier syntaktisch nicht korrekt?
>
>var
> a: array [0..3] of IrgendwasTyp;
>begin
> a[5] := Irgendwas;
>end;


Eh, Felix, das kannst du so nie kompilieren. Aber so:

var
a: array[0..3] of IrgendWasTyp;
i: Integer; // oder Byte oder ShortInt oder Word oder....
begin
i := 5;
a[i] := Irgendwas;
end;

Das ist aber sehr offensichtlich falsch, da es a[5] mit Sicherheit
nicht gibt. Wird aber kompiliert und auch ausgeführt (bis zum Fehler).

Es muß ja immer sichergestellt sein, daß a[Index] auch existiert und
in dem Speicherbereich (hier: Array) liegt, auf dem du zugreifst. Wie
man das sicherstellt, entweder mit automatischer Bereichprüfung oder
mit "manueller", sei dann dem Programmierer überlassen (finde ich).
Hier wäre wohl die automatische angebrachter.

Rudy


Martin

unread,
Mar 10, 1998, 3:00:00 AM3/10/98
to

In article <3503AD12...@pride.de>, fe...@pride.de says...

> Peter Hellinger wrote:
> >
> > Gunar Scholz schrieb in Nachricht <350074F4...@pride.de>...
> > >Ich habe Peter Hellinger's Argumentation so verstanden:
> >
> > Ich sagte nicht "es wird", ich sagte "es kann".
>
> Aber was da ueberschrieben werden "kann" hast du immer noch nicht
> gesagt.
>

Die [0..0] methode hat allerdings keinerlei Nachteil gegenüber der [0..Maxint/size of (was
weis ich)] Methode. (Allerdings auch keinen Vorteil. Der in der Deklaration gesparte
Tippaufwand kommt mit den $R+-)


VORRAUSGESETZUNG IST: (für hat keine Nachteile)

Das du Immer Fehlerfrei arbeitest 100% !!!

Denn nicht umsonst kontrolliert der Compiler (während der Entwichklungszeit) dein Projekt auf
bestimmte Fehler. (Die halt vorkommen und seien es auch nur Tippfehler / und such mal in einem
Projekt von zig 1000 Zeilen)

Zwar wird in besagten Array belibiger grösse auch bei eingeschaltetem Rangecheck, eine
Übertretung wohl in den seltesten Fällen gemerkt. Das hängt aber von der grösse der in dem
Array gespeicherten Daten ab. Sind es Byte Merkt der Rangecheck die überschreitung erst bei
Index > Maxint (kommt wohl selten vor), auch wenn zur Laufzeit nur 100 Byte alloziert sind.
Ist es aber ein Array of record, mit einer recordgrösse von 200 Byte, kann der Rangecheck
schon Zufallstreffer liefern (wenn nämlich auf elemente über Maxint/200 zugegriffen werden
soll)

Aber es kann ja auch durch einen Tippfehler,oder BEdienfehler (bei einfügung durch Makro) der
Rangecheck versehentlich ausbleiben und dann verzichtest du auch für andere Arrays (fester
Grösse) auf die Überprüfung. (und mit etwas Pech übersieht man einen Fehler und veröffentlicht
das Programm).

Durch genau diese ständige R+ R- kann bei einem Tippfehller auch in der Veröffentlichen
Version (in der man aus Zeitgründen globales R- möchte) ein Teil mit R+ übersetzt werden.

Selbstverständlich nichts davon muss eintreten, aber kann.
Manches in beiden Versionen, maches aber nur in der [0..0] Version.

Daher also die Frage, wenn ich eine Möglichkeit habe ohne Mehrarbeit (!) mein Programm vor
einigen Fehlerquellen zu schützen, warum soll ich es nicht tun ??

--
--
Martin

Rudy Velthuis

unread,
Mar 10, 1998, 3:00:00 AM3/10/98
to

Peter Hellinger schrieb in Nachricht <6e1m1g$aet$2...@news.nacamar.de>...


>Gunar Scholz schrieb in Nachricht <35039895...@pride.de>...
>>Es war nicht meine primaer Absicht mit diesem Posting die
[0..0]-Gegner
>>zu ueberzeugen. Ich wollte sie herausfordern, mir endlich klar zu
>>zeigen, was da Negatives passieren soll. Offensichtlich koennen sie
das
>>aber nicht...
>
>
>Ich habe es 6 x (in Worten: Sechs) dargelegt. Wie oft soll ich es
deiner
>Meinung nach noch darlegen?


Hast du nicht. Was wird denn nun überschrieben und wann? Oder was
"kann" überhaupt überschreiben werden und wann?

Also einmal würde schon reichen. Aber dann nur in aller Deutlichkeit.

Also was? Index? Wert im Array? Variable, die Array-Wert aufnimmt?
Oder was sonst?

>Daß es auf einem konkreten Rechner mit konkretem Compiler und
konkretem
>Programm _scheinbar_ kein Fehler auftritt, ist doch kein Beweis für
die
>Fehlerfreiheit der Routine! Umsonst würde der Compiler ja nicht
meckern,
>oder?


Ehrlich gesagt: der Compiler meckert gar nicht. Die
Bereichsüberprüfuing zur Laufzeit schon. Aber das meintest du ja wohl.
Wenn du aber den Code ansiehst, der generiert wird, wirst du sehen,
daß nichts unbeabsichtigt überschrieben werden *kann*.

Auch wenn der Code nicht das Argument ist (und nun zum letzten mal):
Es wird *nie* etwas unbeabsichtigt überschrieben. Die Berechnung ist
einfach Zeigerarithmetik. Ich muß natürlich aufpassen, daß der zu
berechnende Zeioger gültig ist. Das muß ich mit dem Index machen, aber
manuell, da die Bereichsprüfung den Index sowieso nur auf allgemeine
Maximalwerte überprüft, nicht auf konkrete Maximalwerte für das
vorliegende Array (oder den Speicherbereich, den ich als Array
referenziere). Wenn ich also einen Speicherbereich mit 100 Integer
habe, muß ich bei beiden Methoden sorgen, daß der Index nicht über 99
hinausgeht. Der Maximalwert für den Range-Check wäre aber $1FFFFFFF.
Also greift der range-Check schon mal nicht rechtzeitig ein, sonder
nur bei Index-Werten >= $20000000.

Ich teste also schon selbst auf 0..99. Nun könnte ich vielleicht noch
ein Byte mit einem Integer überschreiben, o.ä.? Nein. Sogar in der
Stellung {$R-} würde Delphi das nicht einmal kompilieren. Und wenn ich
(über einen Umweg, wie z.B. eine Integer-Variable), einen Wert in das
Byte zu schreiben versuchen würde, wie z.B. $56789, würde Delphi
trotzdem nur eins von den Bytes, die der Integer $56789 umfaßt,
speichern (in Delphi immer das niedrige). Delphi (und nicht nur
Delphi) speichert nämlich in eine Variable immer nur das, was paßt,
egal wo's her kommt. Das ist aber natürlich schlechter Stil. Also muß
ich auch dabei aufpassen, daß ich nur Werte schreibe (oder lese), die
"passend" sind. In Eigenverantwortung. (Oder eben mit der
automatischen Bereichsprüfung in der [0..SehrViel] Methode.)

Ich behaupte nicht, daß das eine elegante oder die einzig richtige
Methode ist. Mit {$R+} ist das alles meistens viel einfacher. Es ist
aber eine risikolos mögliche und daher keine falsche Methode. Punkt.

Rudy

Gunar Scholz

unread,
Mar 10, 1998, 3:00:00 AM3/10/98
to

Peter Hellinger wrote:
>
> Gunar Scholz schrieb in Nachricht <3503AD12...@pride.de>...

> >Was ist denn hier syntaktisch nicht korrekt?
> >
> >var
> > a: array [0..3] of IrgendwasTyp;
> >begin
> > a[5] := Irgendwas;
> >end;
>
> Schalt den Rangecheck ein, und du wirst sehen, daß der Compiler es nicht
> übersetzt. Eindeutig genug?

O.K. Ich korrigiere mein Beispiel folgendermassen: Statt der 5 nehme ich
eine Variable vom Typ Byte (oder Integer oder irgendwas aehnliches), der
ich vor dem Array-Zugriff eine 5 zuweise.

Das kommt im Endeffekt auf das Gleiche heraus, nur dass der Compiler die
Bereichsueberschreitung nicht merkt.

Die Bereichsueberschreitung hat nichts mit korrekter oder falscher
Syntax zu tun.

Sonst muesste das ja auch syntaktisch falsch sein:

var
b: Byte;
begin
a := 200;
a := a+ 100;
end;

Felix

P.S. Da bei einem 'dynamischen Array' die Anzahl der Elemente zum
Entwicklungszeitpunkt nicht feststeht wiederspricht ein Zugriff mit
einem konstanten Ausdruck sowieso der Philosophie dieses Arrays.

Gunar Scholz

unread,
Mar 10, 1998, 3:00:00 AM3/10/98
to

Peter Hellinger wrote:
>
> Daß es auf einem konkreten Rechner mit konkretem Compiler und konkretem
> Programm _scheinbar_ kein Fehler auftritt, ist doch kein Beweis für die
> Fehlerfreiheit der Routine!

Fasse ich also mal zusammen:
(Da wir hier in einer Newsgroup sind, die sich mit einem konkreten
Entwicklungssystem beschaftigt, beziehe ich mich soweit nicht anders
vermerkt immer darauf.)

(1)
type
pa = ^ta;
ta = array [0..0] of Irgendwas;

(2)
type
pa = ^ta;
ta = array [0..MaxMem div SizeOf(Irgendwas)-1] of Irgendwas;

(1,2)
var
a: pa;
i, anz: Integer;
...
GetMem(a, SizeOf(Irgendwas)* anz);
...
if (i >= 0) and (i < anz) then a^[i] := ...;

In beiden Faellen muss der Programmierer sicherstellen, dass sich das
Element i in dem fuer das Array a angeforderten Speicher befindet.
Im Beispiel (1) muss beim Zugriff auf a der RangeCheck {$R-}
ausgeschaltet werden. Bei einem Zugriff auf ein Element >= anz ist
dieser RangeCheck in beiden Faellen nichts wert.
Weitere negative Auswirkungen gibt es konkret fuer Delphi 1..3 nicht
(bzw. wurden nicht nachgewiesen).

Fazit:
Welche Variante eingesetzt wird, muss jeder Programmierer fuer sich
selbst entscheiden.

Felix

Gunar Scholz

unread,
Mar 10, 1998, 3:00:00 AM3/10/98
to

Rudy Velthuis wrote:
>
> Eh, Felix, das kannst du so nie kompilieren.

Stimmt. Beispiel wurde korrigiert und dem lieben Peter erneut mit der
selben Frage vorgelegt.

Felix

Gunar Scholz

unread,
Mar 10, 1998, 3:00:00 AM3/10/98
to

Martin wrote:
>
> (und mit etwas Pech übersieht man einen Fehler und veröffentlicht
> das Programm).

Als Programmierer bist du auch dafuer verantwortlich, dein Programm
unter allen moeglichen Bedingungen und mit sinnvollen _und_ unsinnigen
Eingaben zu testen, um solche Fehler auszuschalten. (Jeder Programmierer
ist zwar auch nur ein Mensch und uebersieht Fehler, aber das ist ein
anderes Thema.)

> Durch genau diese ständige R+ R- kann bei einem Tippfehller auch in der
> Veröffentlichen Version (in der man aus Zeitgründen globales R- möchte)
> ein Teil mit R+ übersetzt werden.

Mit entspechenden {$IFOPT},...-Compilerbefehlen kann man dafuer sorgen,
dass der global eingestellte Wert des Compilerschalters ausserhalb der
betreffenden Zeilen nicht beeinflusst wird.

> Selbstverständlich nichts davon muss eintreten, aber kann.
> Manches in beiden Versionen, maches aber nur in der [0..0] Version.

Bei korrekt programmiertem Mehraufwand (siehe weiter unten) passiert in
beiden Versionen nichts.

> Daher also die Frage, wenn ich eine Möglichkeit habe ohne Mehrarbeit (!)
> mein Programm vor einigen Fehlerquellen zu schützen, warum soll ich es
> nicht tun ??

Ich muss in beiden Faellen dafuer sorgen, dass ich nicht "uebertrete".
Das erreiche ich nicht nur durch einen simplen Compilerschalter. Diese
Art von Array ist immer mit einem Mehraufwand verbunden. Du musst
Speicher anfordern, pruefen, ob die Anforderung geklappt hat, darauf
achten dass das keine Zugriffe ausserhalb des angeforderten Bereiches
erfolgen. Da faellt so ein kleiner Compilerschalter auch nicht mehr ins
Gewicht.

Felix


Martin

unread,
Mar 10, 1998, 3:00:00 AM3/10/98
to

In article <3505960A...@pride.de>, fe...@pride.de says...

> Martin wrote:
> >
> > (und mit etwas Pech übersieht man einen Fehler und veröffentlicht
> > das Programm).
>
> Als Programmierer bist du auch dafuer verantwortlich, dein Programm
> unter allen moeglichen Bedingungen und mit sinnvollen _und_ unsinnigen
> Eingaben zu testen, um solche Fehler auszuschalten. (Jeder Programmierer
> ist zwar auch nur ein Mensch und uebersieht Fehler, aber das ist ein
> anderes Thema.)

Sicher und während des testens hilft $R+, sicher in den betroffenen Arrays eher selten, aber
dennoch kann er selbst da zur Endeckung von Fehlern führen. Dazu nuoch einmal einen teil aus
meiner Originalnachricht:

--


Zwar wird in besagten Array belibiger grösse auch bei eingeschaltetem Rangecheck, eine
Übertretung wohl in den seltesten Fällen gemerkt. Das hängt aber von der grösse der in dem
Array gespeicherten Daten ab. Sind es Byte Merkt der Rangecheck die überschreitung erst bei
Index > Maxint (kommt wohl selten vor), auch wenn zur Laufzeit nur 100 Byte alloziert sind.
Ist es aber ein Array of record, mit einer recordgrösse von 200 Byte, kann der Rangecheck
schon Zufallstreffer liefern (wenn nämlich auf elemente über Maxint/200 zugegriffen werden
soll)

--


> > Durch genau diese ständige R+ R- kann bei einem Tippfehller auch in der
> > Veröffentlichen Version (in der man aus Zeitgründen globales R- möchte)
> > ein Teil mit R+ übersetzt werden.
>
> Mit entspechenden {$IFOPT},...-Compilerbefehlen kann man dafuer sorgen,
> dass der global eingestellte Wert des Compilerschalters ausserhalb der
> betreffenden Zeilen nicht beeinflusst wird.
>

Genau das meinte ich, wenn du eine "IFOPT" Zeile falsch tippst, oder bei einfügung per Macro,
beim späteren Editieren des Files dort einen Tippfehler einbaust, dann hast du den Salat.

Mal abgesehen davon das die vielen "IFOPT" Zeilen, nicht nur wesentlich mehr Tippaufwand
darstellen (als einmal 0..Maxint/sizeof--), beeinträchtigen sie doch auch die Lesbarkeit des
Projektes (in eienm Projekt können so schnell ein paar 100 Zeilen unnötig zusammenkommen).
Und je schlechter die Lesbarkeit, desto schneller schleichen sich weitere Fehler ein.

(JA klar das Endprodukt kann (nach der Compilierung) das gleiche sein. Man hat eben nur etwas
mehr Arbeit. Saicher in einem Projekt in dem ich schon 0..0 habe lohnt es sich evtl nicht
umzustellen, aber in einem Neuen schon)

> > Selbstverständlich nichts davon muss eintreten, aber kann.
> > Manches in beiden Versionen, maches aber nur in der [0..0] Version.
>
> Bei korrekt programmiertem Mehraufwand (siehe weiter unten) passiert in

^^^^^^^^^^^^
> beiden Versionen nichts.
>
Ja, genau. Aber welchen Vorteil erwartest du von dem Mehraufwand.
Oder anders: Warum kompliziert, wenn es auch einfach geht?


> > Daher also die Frage, wenn ich eine Möglichkeit habe ohne Mehrarbeit (!)
> > mein Programm vor einigen Fehlerquellen zu schützen, warum soll ich es
> > nicht tun ??
>
> Ich muss in beiden Faellen dafuer sorgen, dass ich nicht "uebertrete".
> Das erreiche ich nicht nur durch einen simplen Compilerschalter. Diese
> Art von Array ist immer mit einem Mehraufwand verbunden. Du musst
> Speicher anfordern, pruefen, ob die Anforderung geklappt hat, darauf
> achten dass das keine Zugriffe ausserhalb des angeforderten Bereiches
> erfolgen. Da faellt so ein kleiner Compilerschalter auch nicht mehr ins
> Gewicht.
>

Siehe obige Abschnitte, insbesondere den wiederholten Absatz aus meiner Original Mail.

Wenn ich ohne Mehraufwand, auch nur die geingste (vielleicht nur 1 zu 1 Millionen) chance hab
einen weiteren Fehler zu Finden, warum nicht nutzen. Bei irgendwem tritt genau dieser Fehler
mal ein und nur, wenn er nicht 0..0 programmiert hat, wird ihm viel Such und Testarbeit
gespart.


Resume dieser Mail:

Zwar ist die Wahrscheinlichkeuit das man ohne 0..0 weniger Fehler hat gering, so ist doch eben
die 00..Maxint---- Version auch mit weniger Aufwand verbunden. Beides zusammen spricht IMHO
für 0..Maxint----.

--

so far Klaus

Martin

unread,
Mar 10, 1998, 3:00:00 AM3/10/98
to

In article <35059059...@pride.de>, fe...@pride.de says...

> (1)
> type
> pa = ^ta;
> ta = array [0..0] of Irgendwas;
>
> (2)
> type
> pa = ^ta;
> ta = array [0..MaxMem div SizeOf(Irgendwas)-1] of Irgendwas;
>
> (1,2)
> var
> a: pa;
> i, anz: Integer;
> ...
> GetMem(a, SizeOf(Irgendwas)* anz);
> ...
> if (i >= 0) and (i < anz) then a^[i] := ...;
>
> In beiden Faellen muss der Programmierer sicherstellen, dass sich das
> Element i in dem fuer das Array a angeforderten Speicher befindet.
> Im Beispiel (1) muss beim Zugriff auf a der RangeCheck {$R-}
> ausgeschaltet werden. Bei einem Zugriff auf ein Element >= anz ist
> dieser RangeCheck in beiden Faellen nichts wert.
> Weitere negative Auswirkungen gibt es konkret fuer Delphi 1..3 nicht
> (bzw. wurden nicht nachgewiesen).


Im 2. Falle wird beim Zugeriff mit negativen Index ein Fehler ausgelöst, im ersten nicht.

Wenn ich Irgendwo (während der Entwicjklung in der IF zeile einen Fehler habe, kann das im
ersten Falle eher unbemerkt bleiben.


--

so far Klaus

Rudy Velthuis

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Martin schrieb in Nachricht ...

>Zwar wird in besagten Array belibiger grösse auch bei eingeschaltetem
Rangecheck, eine
>Übertretung wohl in den seltesten Fällen gemerkt. Das hängt aber von
der grösse der in dem
>Array gespeicherten Daten ab. Sind es Byte Merkt der Rangecheck die
überschreitung erst bei
>Index > Maxint (kommt wohl selten vor), auch wenn zur Laufzeit nur
100 Byte alloziert sind.
>Ist es aber ein Array of record, mit einer recordgrösse von 200 Byte,
kann der Rangecheck
>schon Zufallstreffer liefern (wenn nämlich auf elemente über
Maxint/200 zugegriffen werden
>soll)

Egal, wie groß der Record, wer alloziert schon tagtäglich (oder
überhaupt irgendwann) 2GB RAM? Vielleicht später, wenn es den 128bit
Hexium IV gibt oder so (also frühestens in 2 Jahren ;).

>> > Durch genau diese ständige R+ R- kann bei einem Tippfehller auch
in der
>> > Veröffentlichen Version (in der man aus Zeitgründen globales R-
möchte)
>> > ein Teil mit R+ übersetzt werden.
>>
>> Mit entspechenden {$IFOPT},...-Compilerbefehlen kann man dafuer
sorgen,
>> dass der global eingestellte Wert des Compilerschalters ausserhalb
der
>> betreffenden Zeilen nicht beeinflusst wird.
>>
>Genau das meinte ich, wenn du eine "IFOPT" Zeile falsch tippst, oder
bei einfügung per Macro,
>beim späteren Editieren des Files dort einen Tippfehler einbaust,
dann hast du den Salat.
>
>Mal abgesehen davon das die vielen "IFOPT" Zeilen, nicht nur
wesentlich mehr Tippaufwand
>darstellen (als einmal 0..Maxint/sizeof--), beeinträchtigen sie doch
auch die Lesbarkeit des
>Projektes (in eienm Projekt können so schnell ein paar 100 Zeilen
unnötig zusammenkommen).
>Und je schlechter die Lesbarkeit, desto schneller schleichen sich
weitere Fehler ein.


Na ja, ich würde einen Zugriff, der sowieso mit Mehraufwand verbunden
ist (Überprüfung des Index, usw.) nur einmal kodieren, in einer
eigenen Routine, und nicht zigmal wieder neu. Der Aufruf hätte dann
nicht die {$IFOPT....}.

>Wenn ich ohne Mehraufwand, auch nur die geingste (vielleicht nur 1 zu
1 Millionen) chance hab
>einen weiteren Fehler zu Finden, warum nicht nutzen. Bei irgendwem
tritt genau dieser Fehler
>mal ein und nur, wenn er nicht 0..0 programmiert hat, wird ihm viel
Such und Testarbeit
>gespart.


Es spricht für die 0..MaxEtwas methode, daß sie einfacher ist. Das
gebe ich vollmundig zu. Die 0..0 Methode ist dadurch aber nicht FALSCH
(nur vielleicht etwas umständlicher). Und das wurde mehrmals (übrigens
nicht von dir!) behauptet. Dagegen haben Felix (Gunar Scholz) und ich
Argumente angeführt. Welche Methode man benutzt, ist wohl eher
persönliche Präferenz.

Rudy


Rudy Velthuis

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Martin schrieb in Nachricht ...

>> In beiden Faellen muss der Programmierer sicherstellen, dass sich
das
>> Element i in dem fuer das Array a angeforderten Speicher befindet.
>> Im Beispiel (1) muss beim Zugriff auf a der RangeCheck {$R-}
>> ausgeschaltet werden. Bei einem Zugriff auf ein Element >= anz ist
>> dieser RangeCheck in beiden Faellen nichts wert.
>> Weitere negative Auswirkungen gibt es konkret fuer Delphi 1..3
nicht
>> (bzw. wurden nicht nachgewiesen).

>Im 2. Falle wird beim Zugeriff mit negativen Index ein Fehler
ausgelöst, im ersten nicht.
>
>Wenn ich Irgendwo (während der Entwicjklung in der IF zeile einen
Fehler habe, kann das im
>ersten Falle eher unbemerkt bleiben.


Stimmt. Aber wenn du irgendwo einen Fehler hast, kann das sowieso
lange Zeit unbemerkt bleiben. Die Methode [0..0] muß natürlich sehr
sorgfältig benutzt werden. Das muß aber die [0..SehrViel]-Methode
auch. Da darf auch kein Fehler in der Zeile "if (i >= 0) and (i <=
anz) then" stehen. Soviel sicherer ist die [0..SehrViel]-Methode nun
wirklich nicht. Es werden aber vom Range-Check natürlich einige
unwahrscheinliche Werte abgefangen.

Wie ich schon in einer anderen Mail sagte, würde ich den Zugriff auf
das Array nur einmal kodieren, in einer eigenen Routine. Die müßte
dann mit der größten Vorsicht kodiert sein, egal welche Methode für
die Deklaration verwendet wurde. Aber, wer es nicht schafft, eine
Zeile wie "if (i >= 0) and (i <= anz) then" zu kodieren, sollte lieber
Schafe hüten oder Brötchen backen (sehr ehrenwerte Berufe übrigens,
ich will hier niemanden beleidigen ;).

Rudy

Gunar Scholz

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Martin wrote:
>
> Wenn ich Irgendwo (während der Entwicjklung in der IF zeile einen
> Fehler habe, kann das im
> ersten Falle eher unbemerkt bleiben.

Deine Fehler sind dein Problem, nicht meins...

Felix


Peter Hellinger

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Rudy Velthuis schrieb in Nachricht <35058...@news2.cityweb.de>...


>Also einmal würde schon reichen. Aber dann nur in aller Deutlichkeit.


Lies meine mails zu dem Thema. Steht alles drin.

Helli


Peter Hellinger

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Gunar Scholz schrieb in Nachricht <3505960A...@pride.de>...

>Ich muss in beiden Faellen dafuer sorgen, dass ich nicht "uebertrete".
>Das erreiche ich nicht nur durch einen simplen Compilerschalter. Diese
>Art von Array ist immer mit einem Mehraufwand verbunden. Du musst
>Speicher anfordern, pruefen, ob die Anforderung geklappt hat, darauf
>achten dass das keine Zugriffe ausserhalb des angeforderten Bereiches
>erfolgen. Da faellt so ein kleiner Compilerschalter auch nicht mehr ins
>Gewicht.


Aber umso leichter unter den Tisch...

Man sieht hier wieder deutlich, daß deine Überlegungen reine Theorie sind um
das Rangecheck-Argument vom Tisch zu wischen, aber keinesfalls aus deiner
praktischen Anwendung stammt.

Mit dem Compilerschalterchen ist es ja nicht getan, man muß hier ja ein
conditional define vereinbaren, denn leider kennt Delphi kein {$R=}, wie
andere Compiler das tun. Beispiel:

PROCEDURE Blafasel;
VAR x: ARRAY [0..0] OF BYTE;
i: BYTE;
BEGIN
... irgendwelcher Code zum allozieren etc. ...
i:= 95;
{$R-} // Rangecheck aus sicherstellen
x[i]:= 0:
{$R+} // Rangecheck wieder ein
END;

PROCEDURE FaselFasel;
VAR x: ARRAY [0..0] OF BYTE;
i: BYTE;
BEGIN
... irgendwelcher Code zum allozieren etc. ...
i:= 95;
{$R-} // Rangecheck aus sicherstellen
BlaFasel;
x[i]:= 0:
{$R+} // Rangecheck wieder ein
END;

Der Zugriff auf x in FaselFasel erzeugt einen Laufzeitfehler.

Zum reaktivieren des Rangecheck mußt du ganz schöne Logik anwenden:

{$IFOPT R+} // Rangecheck an?
{$DEFINE RCON} // Merken!
{$R-} // Rangecheck aus
{$ENDIF}

x[i]:= 0:

{$IFDEF RCON} // RC Angewesen?
{$UNDEF RCON} // Define in kontollierten Zustand bringen
{$R+} // RC wieder einschalten
{$ENDIF}

Unserm lieben Rudy war ja schon meine definierte Array-Deklaration zuviel
zum Denken und Schreiben, was wird er *da* wohl sagen - und das bei *jedem*
Zugriff auf das Array?

Helli


Peter Hellinger

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Rudy Velthuis schrieb in Nachricht <3505c...@news1.cityweb.de>...

>Egal, wie groß der Record, wer alloziert schon tagtäglich (oder
>überhaupt irgendwann) 2GB RAM? Vielleicht später, wenn es den 128bit
>Hexium IV gibt oder so (also frühestens in 2 Jahren ;).

Dadrum gehts doch gar nicht. Es geht nach wie vor drum, daß die Deklaration
von 0..0 als Arraybereich dich zwingt auf Sicherheitsmaßnahmen während der
Entwicklung zu verzichten. Desweiteren kommt hinzu, daß du keinerlei
Sicherheit hast, daß der erzeugte Code tatsächlich das tut was er soll. Wie
gesagt: Das ein konkreter Code von einem konkretem Compiler auf einer
konkretem Maschine keinen Fehler erzeugt ist kein Indiz dafür, daß kein
Fehler existiert. Es ist für einen Programmierer IMMER gefährlich Annahmen
über die Codeerzeugung oder die Zielmaschine zu machen. Deshalb verwendet
man ja höhere Programmiersprachen, um von solchen Annahmen befreit zu sein.

Helli

Rudy Velthuis

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Peter Hellinger schrieb in Nachricht <6e6j60$ln7$1...@news.nacamar.de>...


Eben nicht. Lies mal meine Antworten.

Rudy


Matthias Watermann

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Rudy schrieb am 10.03.98 in <35058...@news2.cityweb.de>:

> [...]


> Wenn ich also einen Speicherbereich mit 100 Integer
> habe, muß ich bei beiden Methoden sorgen, daß der Index nicht über 99
> hinausgeht. Der Maximalwert für den Range-Check wäre aber $1FFFFFFF.
> Also greift der range-Check schon mal nicht rechtzeitig ein, sonder
> nur bei Index-Werten >= $20000000.

Bei allen Werte-Bereichen (z.B. für Arrays, aber auch
andere Variablen) deren Werte nicht einem generischen Datentyp
entsprechen, definiere ich einen eigenen Datentyp. Für Dein
Beispiel könnte das ungefähr so aussehen:

Const
MaxArrayIdx = 100;
Type
tArrayInt = 1..MaxArrayIdx;
tMyArray = Array[tArrayInt] Of Integer;
Var
MyArray : tMyArray;
MyIndex : tArrayInt;

Und da paßt dann der Kompiler auch schon auf ...

--
Matthias

Liebe Deine Feinde, aber sei schneller als sie.

Rudy Velthuis

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Peter Hellinger schrieb in Nachricht <6e6j61$ln7$2...@news.nacamar.de>...


>
>Zum reaktivieren des Rangecheck mußt du ganz schöne Logik anwenden:
>
>{$IFOPT R+} // Rangecheck an?
>{$DEFINE RCON} // Merken!
>{$R-} // Rangecheck aus
>{$ENDIF}
>
> x[i]:= 0:
>
>{$IFDEF RCON} // RC Angewesen?
>{$UNDEF RCON} // Define in kontollierten Zustand bringen
>{$R+} // RC wieder einschalten
>{$ENDIF}
>
>Unserm lieben Rudy war ja schon meine definierte Array-Deklaration
zuviel
>zum Denken und Schreiben, was wird er *da* wohl sagen - und das bei
*jedem*
>Zugriff auf das Array?

Hier ist er. Er sagt folgendes:

Dieser Range-Check-Check kann einfacher:

{$DEFINE REALESE} // nur einmal definieren.
{$IFDEF RELEASE} {$R-} {$ENDIF}

...

{$R-}
x[i] := 0;
{$IFNDEF RELEASE} {$R+} {$ENDIF}

Zweitens würde ich den Zugriff auf das Array ja zentralisieren, also
in eine eigene Routine packen, die dann gleich auf die wirklichen
Grenzen des als Array benutzten Speicherbereichs überprüft. Da muß ich
also nicht mehr soviel schreiben und habe ich nur eine, definierte
Stelle. Wenn also doch noch ein Zugriffsfehler auftreten sollte (ich
kann mich ja vertippen), weiß ich, wo ich o.a. suchen muß.

Ich würde das gleiche aber auch bei der [0..SehrViel]-Methode
empfehlen. Die ist ja auch nicht narrensicher, da auch bei dieser
Methode "manuell" auf die tatsächlichen Grenzen des Arrays gecheckt
werden muß.

Übrigens: Schreiben ist ja nicht gerade etwas, worin ich faul bin
(sieh dir mal die Anzahl Mails von uns beiden nur über dieses Thema an
;). Und über die Definitionen habe ich auch lange genug nachgedacht.

Ich denke z.B. immer noch über TBitmapInfo nach. Da wird die
Definition mit [0..SehrViel] ja noch komplizierter:

type
TBitmapInfo = packed record
bmiHeader: TBitmapInfoHeader;
bmoColors: array[0..(MaxMemory - SizeOf(TBitmapInfoHeader)) div
SizeOf(TRGBQuad) - 1] of TRGBQuad;
end;

Das muß man aber so machen, sonst kompiliert Delphi das nicht. Delphi
kompiliert aber anstandlos die [0..0] Definition in Windows.pas.

Und wie macht Borland das bei:

typedef struct tagEMRPOLYDRAW
{
EMR emr;
RECTL rclBounds;
DWORD cptl;
POINTL aptl[1];
BYTE abTypes[1];
} EMRPOLYDRAW, *PEMRPOLYDRAW;

Genau: Borland macht daraus

PEMRPolyDraw = ^TEMRPolyDraw;
TEMRPolyDraw = record
emr: TEMR;
rclBounds: TRect; { Inclusive-inclusive bounds in device units}
cptl: DWORD; { Number of points}
aptl: array[0..0] of TPoint; { Array of points}
abTypes: array[0..0] of Byte; { Array of point types}
end;

Wie würdest du das aber mit der [0..SehrViel] Methode beschreiben? Gar
nicht. Die Deklaration hier oben ist zwar auch nicht 100% brauchbar,
da ich nicht ohne Tricks auf die abTypes zugreifen kann, aber
kompilierbar.

Und gerade für solche verzwickte API-Definitionen ist die
[0..0]-Methode geeignet. Nicht für 08-15 Arrays mit variablen (m.a.W.
zur Design-Zeit unbekannten) Größen, sonder für variable Arrays in
Records, wie das WINAPI und andere APIs sie schon mal loslassen. Und
für solche Sachen kannst du dich auch nicht mehr auf einen Range-Check
verlassen, da du schon genug tricksen mußt mit Zeigern o.ä.

Rudy


Rudy Velthuis

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Matthias Watermann schrieb in Nachricht
<6pfX$CB9...@dfg.oln.ComLink.APC.org>...


Matthias,

wir reden hier nicht von Arrays mit einer bekannten Größe (Anzahl
Elementen), sondern gerade über Arrays "ohne Grenzen". Wenn ich also
ein Array unbekannter Größe deklariere, und zwar mit
[0..EtwasSehrHohes], um auf ein Array zuzugreifen, daß vielleicht in
Wirklichkeit (zur Run-Time) mal 100 Elemente hat (also 0 bis einschl.
99), hilft dir deine Deklaration herzlich wenig.

Da hilft dir aber auch nicht die Bereichsprüfung, da die nur auf 0 und
EtwasSehrHohes überprüft. Wenn ich dann 200 als Index benutzen würde,
hätte ich eine mögliche Zugriffsverletzung, obwohl meine
Bereichsprüfung sagen würde, daß alles paletti ist, da 0 < 200 <
EtwasSehrHohes. Ich muß also dafür sorgen, daß ich nicht über 99
indiziere. Dieser Wert 100 wird mir aber erst zur Laufzeit bekannt,
z.B. bei offenen Arrays als High(MyArray).
Also muß ich einen eigenen Laufzeit-Check kodieren. Das muß ich bei
beiden Methoden, egal, ob [0..0] oder [0..EtwasSehrHohes].

N.B.: Mit "EtwasSehrHohes" meine ich natürlich so etwas wie "MaxMemory
div SizeOf(Element) - 1". MaxMemory ist in D2/D3 dann $7FFFFFFF.

Rudy

Rudy Velthuis

unread,
Mar 12, 1998, 3:00:00 AM3/12/98
to

Peter Hellinger schrieb in Nachricht <6e6j8p$luh$1...@news.nacamar.de>...


>Rudy Velthuis schrieb in Nachricht <3505c...@news1.cityweb.de>...
>>Egal, wie groß der Record, wer alloziert schon tagtäglich (oder
>>überhaupt irgendwann) 2GB RAM? Vielleicht später, wenn es den 128bit
>>Hexium IV gibt oder so (also frühestens in 2 Jahren ;).
>
>Dadrum gehts doch gar nicht. Es geht nach wie vor drum, daß die
Deklaration
>von 0..0 als Arraybereich dich zwingt auf Sicherheitsmaßnahmen
während der
>Entwicklung zu verzichten.

Auf diese kann ich mich in diesem Fall sowieso nicht stützen, also
sind die da nicht so wichtig. Ich muß ja immer noch ein manuelle
Überprüfung machen, egal ob mit oder ohne $R+.

>Desweiteren kommt hinzu, daß du keinerlei
>Sicherheit hast, daß der erzeugte Code tatsächlich das tut was er
soll. Wie
>gesagt: Das ein konkreter Code von einem konkretem Compiler auf einer
>konkretem Maschine keinen Fehler erzeugt ist kein Indiz dafür, daß
kein
>Fehler existiert. Es ist für einen Programmierer IMMER gefährlich
Annahmen
>über die Codeerzeugung oder die Zielmaschine zu machen. Deshalb
verwendet
>man ja höhere Programmiersprachen, um von solchen Annahmen befreit zu
sein.


Manchmal muß man mit dieser hohen Programmiersprache in die
Niederungen eines Windows-API oder ähnliches abtauchen. Da muß man
sich schon auf die Struktur eines Arrays verlassen können. Und Arrays
sind ja immer kontinuierliche Folgen von Elementen. Das müssen wir ja
annehmen, sonst kannst du ja mit der [0..Max]-Deklaration auch nicht
auf ein Array zugreifen.

Auch du mußt dich darauf verlassen, daß ein Array[0..Max] sich genauso
verhält, wie ein Array[0..99] oder Array[0..291] oder Array[0..12345]
usw. und daß immer der gleiche Code dabei herauskommt, und nicht ein
Index wegen deiner Deklaration zu einem Longint expandiert wird, wo es
vielleicht in einem Byte oder Wort (für den tatsächlichen Wert) passen
sollte. Wir können beide davon ausgehen, daß die Deklaration paßt.
Wenn ich dann in das CPU-Fenster schaue, sehe ich auch tatsächlich,
daß das so ist (in allen mir bekannten Delphi-Versionen und in BP7).
Wahrscheinlich auch in TP6, TP5.5, TP5, TP4.

Ubrigens: Borland benutzt diese [0..0]-Methode sowohl in der VCL als
in der RTL. Wenn das unsicher wäre, wäre ja die ganze RTL/VCL
unsicher. Das kann ich mir nicht vorstellen. So dumm stellen die sich
ja auch sonst bei Borland nicht an. (Sowohl RTL als VCL sind sehr
efficient und sicher programmiert. Schau dir doch einfach einmal das
Ressourcen-Management von Delphi an. Das ist sehr efficient und
trotzdem sicher. Der Anwendungsprogrammierer kann da mit den
Ressourcen wüten wie er will, wenn er nicht selbst in das Management
eingreift, geht nichts verloren. Trotzdem ist das
Ressourcen-Management ziemlich schnell.)

Rudy

Peter Hellinger

unread,
Mar 12, 1998, 3:00:00 AM3/12/98
to

Rudy Velthuis schrieb in Nachricht <35071...@news1.cityweb.de>...

>{$DEFINE REALESE} // nur einmal definieren.
>{$IFDEF RELEASE} {$R-} {$ENDIF}
>
>...
>
>{$R-}
>x[i] := 0;
>{$IFNDEF RELEASE} {$R+} {$ENDIF}

Ich benutze diesen conditional define Kram so gut wie nie (bei mir findest
du auf 30 Mb Source vielleicht 100 solcher Dinger), aber irgendwie habe ich
den Eindruck, daß das nicht das tut, was ich aufschrieb (feststellen ob,
abschalten, und abhängig von "ob" wieder einschalten)

>Ich würde das gleiche aber auch bei der [0..SehrViel]-Methode
>empfehlen. Die ist ja auch nicht narrensicher, da auch bei dieser
>Methode "manuell" auf die tatsächlichen Grenzen des Arrays gecheckt
>werden muß.

Ich würde eine vernünftige Liste verwenden, und keinen Array... 8-)

>Ich denke z.B. immer noch über TBitmapInfo nach. Da wird die
>Definition mit [0..SehrViel] ja noch komplizierter:
>
>type
> TBitmapInfo = packed record
> bmiHeader: TBitmapInfoHeader;
> bmoColors: array[0..(MaxMemory - SizeOf(TBitmapInfoHeader)) div
>SizeOf(TRGBQuad) - 1] of TRGBQuad;
> end;

Ja und? Das macht man auch nicht on the fly im Array, sondern vorher in
einer Konstanten. Bei der Gelegenheit kann man gleich einen Typ für
den Zähler deklarieren, dann überwacht der Compiler alles automatisch.

>Das muß man aber so machen, sonst kompiliert Delphi das nicht. Delphi
>kompiliert aber anstandlos die [0..0] Definition in Windows.pas.

Jetzt tu doch bitte nicht, als ob das andere nicht "anstandslos" compiliert
würde. 8-(

>
>Und wie macht Borland das bei:
>
>typedef struct tagEMRPOLYDRAW
>{
> EMR emr;
> RECTL rclBounds;
> DWORD cptl;
> POINTL aptl[1];
> BYTE abTypes[1];
>} EMRPOLYDRAW, *PEMRPOLYDRAW;

>
>Genau: Borland macht daraus
>
> PEMRPolyDraw = ^TEMRPolyDraw;
> TEMRPolyDraw = record
> emr: TEMR;
> rclBounds: TRect; { Inclusive-inclusive bounds in device units}
> cptl: DWORD; { Number of points}
> aptl: array[0..0] of TPoint; { Array of points}
> abTypes: array[0..0] of Byte; { Array of point types}
> end;
>

>Wie würdest du das aber mit der [0..SehrViel] Methode beschreiben? Gar
>nicht.

Warum nicht? Grundsätzlich muß man sagen, daß die C-Deklartion eine
Schweinerei erster Güte ist (sogar für C!), und daß der Typ, der das
verbrochen hat, einen Tag lang an seinen Füßen aufgehängt gehört, damit er
sowas in Zukunft unterläßt. Die Startadresse von abTypes kann man weder in C
noch in Pascal ohne Rechnerei feststellen. 8-( Die "Struktur", so wie sie
aufgeschrieben ist, existiert als solche also gar nicht.

Nur um klarzulegen, ob ich das auch richtig verstanden habe: aptl ist eine
beliebig lange Liste von TPoint; und abTypes ist eine darauf folgende
beliebig lange Liste von Bytes wobei cptl jeweils die aktuelle Länge der
Liste angibt. Ich nehme an, daß der Index von aptl mit dem von apTypes
korreliert. Wenn man nur 1 Minute nachdenkt, wird man feststellen, daß es
dafür - wie immer - eine ganz saubere Pascal-Lösung gibt. Es gibt eben
nichts, was man nicht sauber in Pascal lösen könnte 8-):

CONST MaxPoints = MaxMemory DIV SizeOf (TPoint);

TYPE tAptl = ARRAY [0..MaxPoints] OF TPoint;
pAptl = ^tAptl;

TYPE tabTypes = ARRAY [0..MaxPoints] OF BYTE;
pabTypes = ^tabTypes;

TYPE PEMRPolyDraw = ^TEMRPolyDraw;


TEMRPolyDraw = record
emr: TEMR;
rclBounds: TRect; Inclusive-inclusive bounds in device
units}
cptl: DWORD; { Number of points}

xxx: BYTE; // Es folgt ein beliebig langer
Speicherbereich,
// Miesester C-Code halt.. 8-(
end;

Wie gesagt, die "Struktur" läßt sich ohne Rechnerei nicht auflösen (auch
nicht in C):

VAR ppd: PemprPolyDraw;
aptl: pAptl;
abTypes: pabTypes;
BEGIN
ppd:= IrgendeineFunktionDieDieBasisAdresseLiefert;
aptl:= @ppd^.xxx;
abTypes:= POINTER (LONGINT(aptl) + (ppd^.cptl * SizeOf(TPoint)));

Fertisch ist der Balkong. Wenn man mehrere PemprPolyDraw braucht, fasst man
die obige Deklaration in einen eigenen Typ:

TYPE MyPemprPolyDraw = RECORD
ppd: PEMPRPolyDraw;
aptl: pAptl;
abTypes: pabTypes;
END;

>Und gerade für solche verzwickte API-Definitionen ist die
>[0..0]-Methode geeignet.

Denkbar ungeeignet in diesem Falle, denkbar ungeeignet!!! Denn wie du schon
schreibst: Ohne Tricks kannst du nicht auf abTypes zugreifen. In meiner
Version dagegen schon...

>... Und


>für solche Sachen kannst du dich auch nicht mehr auf einen Range-Check
>verlassen, da du schon genug tricksen mußt mit Zeigern o.ä.

Tja. Das es anders, Pascal-konform und sauber mit Rangechecks geht, habe ich
gerade aufgezeigt...

Helli

Peter Hellinger

unread,
Mar 12, 1998, 3:00:00 AM3/12/98
to

Rudy Velthuis schrieb in Nachricht <35071...@news1.cityweb.de>...
>Auf diese kann ich mich in diesem Fall sowieso nicht stützen, also
>sind die da nicht so wichtig. Ich muß ja immer noch ein manuelle
>Überprüfung machen, egal ob mit oder ohne $R+.


Wir waren doch ein paar Mails weiter vorne beinahe der einingen Meinung, daß
wenn der Tippaufwand hoch ist, eine Geschichte wie "{$R-} Code {$R+}" eher
nicht gemacht wird. Und wer sagt, daß ein Rangecheck nicht wichtig ist, hat
immer noch nicht begriffen wozu ein Rangecheck da ist (nicht um den Heap zu
überwachen, sondern um Code/Data zu überwachen).

>Manchmal muß man mit dieser hohen Programmiersprache in die
>Niederungen eines Windows-API oder ähnliches abtauchen. Da muß man
>sich schon auf die Struktur eines Arrays verlassen können. Und Arrays
>sind ja immer kontinuierliche Folgen von Elementen. Das müssen wir ja
>annehmen, sonst kannst du ja mit der [0..Max]-Deklaration auch nicht
>auf ein Array zugreifen.


Auch darum geht es mir nicht. Ich will darauf hinaus, daß du und Felix
Maschinencode gezeigt haben, bei denen ein Überschreiben von Fremden
Speicher unwahrscheinlich ist (weil im Register mit kontrolliertem Schreiben
auf dem Speicher). Wer garantiert, daß immer und unter allen Umständen
solcher Code erzeugt wird? Was ist, wenn der Compiler gerade kein Register
mehr übrig hat (verschachteltes WITH)? Was passiert, wenn jemand bei Borland
Arrayzugriffe mittels DMA zu bewerkstelligen? Klingt alles
unwahrscheinlich, aber hast du eine Garantie, daß dem nicht so sein wird?
Wieviel Leute sind mit ihrem Code von D1 nach D2 auf die Schnauze gefallen?
Wieviele Leute sind von D2 auf D3 ausgerutscht? Wievel werden wohl bei D3
auf D4 ihren Code überarbeiten müssen?

Als Hochsprachenprogrammierer interessiert mich es nicht, welchen
Maschinencode der Compiler erzeugt. Mein Quellcode ist eine Abstraktion
einer virtuellen Maschine. Wenn ich zB. die unterschiedlichen OS-Aufrufe
weglasse (bzw. in eine plattformabhängige Library packe) müßte es einem
Hochsprachen-Quellcode egal sein, welcher konkreter Prozessor
dahintersteckt, vorausgesetzt ich habe nicht Quellcode geschrieben, der sich
auf bestimmte Maschineneigenschaften verläßt. Bestes Beispiel ist C und
Unix: Unix gibt es auf einer vielzahl von Hardware-Plattformen, die
teilweise nicht unterschiedlicher sein können. Dennoch kann man in der Regel
ein C-Programm für Unix im Quellcode nehmen und auf jeder beliebigen
Hardware einfach neu compilieren.

>Wenn ich dann in das CPU-Fenster schaue, sehe ich auch tatsächlich,
>daß das so ist (in allen mir bekannten Delphi-Versionen und in BP7).
>Wahrscheinlich auch in TP6, TP5.5, TP5, TP4.


Hast du jemand, der das garantiert? Steht das irgendwo schriftlich in den
Borland-Handbüchern?


>Ubrigens: Borland benutzt diese [0..0]-Methode sowohl in der VCL als
>in der RTL.

Weil sie eine falsche C-Deklaration ohne Sinn und Verstand nachprogrammiert
haben.

>Wenn das unsicher wäre, wäre ja die ganze RTL/VCL
>unsicher.

Es ist unsicher, wenn man auf die Elemente zugreift.

>Das kann ich mir nicht vorstellen. So dumm stellen die sich
>ja auch sonst bei Borland nicht an.

Da kann man geteiliter Meinung sein.

Helli


Rudy Velthuis

unread,
Mar 12, 1998, 3:00:00 AM3/12/98
to

Peter Hellinger schrieb in Nachricht <6e800m$b96$2...@news.nacamar.de>...


>Rudy Velthuis schrieb in Nachricht <35071...@news1.cityweb.de>...

>>{$DEFINE REALESE} // nur einmal definieren.
>>{$IFDEF RELEASE} {$R-} {$ENDIF}
>>
>>...
>>
>>{$R-}
>>x[i] := 0;
>>{$IFNDEF RELEASE} {$R+} {$ENDIF}
>
>Ich benutze diesen conditional define Kram so gut wie nie (bei mir
findest
>du auf 30 Mb Source vielleicht 100 solcher Dinger), aber irgendwie
habe ich
>den Eindruck, daß das nicht das tut, was ich aufschrieb (feststellen
ob,
>abschalten, und abhängig von "ob" wieder einschalten)


Nein. Warum feststellen ob? Aus ist aus, auch wenn es schon aus war.
Und an nur, wenn ich nicht in der Release-Version bin. Es gibt da ja
nicht soviele Möglichkeiten.

Also noch einmal, mit Kommentar:

{$DEFINE RELEASE}
-- ist ja klar, wann und wofür
{$IFDEF RELEASE} {$R-} {$ENDIF}
-- $R Nur in der Release-Version ausschalten (ganz oben in der Datei).

{$R-}
-- Ist ja unabhängig von Release oder nicht. Immer aus hier.


x[i] := 0;
{$IFNDEF RELEASE} {$R+} {$ENDIF}

-- In Release so belassen (R-), sonst wieder einschalten.

Klar jetzt? Du bräuchtest ja nicht zu wechseln (toggle), sonder nur
immer vor dem Arrayzugriff auszuschalten und danach, abhängig von
RELEASE, wieder einzuschalten oder nicht.

>>Ich würde das gleiche aber auch bei der [0..SehrViel]-Methode
>>empfehlen. Die ist ja auch nicht narrensicher, da auch bei dieser
>>Methode "manuell" auf die tatsächlichen Grenzen des Arrays gecheckt
>>werden muß.
>
>Ich würde eine vernünftige Liste verwenden, und keinen Array... 8-)

[Wir reden aber über offene Arrays (oder Arrays "ohne Grenzen", siehe
Betreff-Zeile). Ich würde ja auch oft eine TList o.ä. verwenden. Wenn
ich aber
auf ein solches Array zugreifen muß, dann nur zentral.]

>>Ich denke z.B. immer noch über TBitmapInfo nach. Da wird die
>>Definition mit [0..SehrViel] ja noch komplizierter:
>>
>>type
>> TBitmapInfo = packed record
>> bmiHeader: TBitmapInfoHeader;
>> bmoColors: array[0..(MaxMemory - SizeOf(TBitmapInfoHeader)) div
>>SizeOf(TRGBQuad) - 1] of TRGBQuad;
>> end;
>
>Ja und? Das macht man auch nicht on the fly im Array, sondern vorher
in
>einer Konstanten. Bei der Gelegenheit kann man gleich einen Typ für
>den Zähler deklarieren, dann überwacht der Compiler alles
automatisch.

Ob vorher als Konstante, oder "on the fly". das kann wirklich viel
Tipparbeit sein. Probier's mal für:

typedef struct _COMM_CONFIG {
DWORD dwSize;
WORD wVersion;
WORD wReserved;
DCB dcb;
DWORD dwProviderSubType;
DWORD dwProviderOffset;
DWORD dwProviderSize;
WCHAR wcProviderData[1];
} COMMCONFIG, *LPCOMMCONFIG;

Das ist dann noch etwas mehr Tipparbeit:

const
MaxCommConfig = (MaxMemory - 4 * SizeOf(DWORD) + 2 * SizeOf(WORD) +
Sizeof(DCB)) div SizeOf(WChar); // wobei MaxMemory = $7FFFFFFF!

...
wcProviderData: array[0..MaxCommConfig - 1] of WChar;
...

Und davon gibt's in einigen APIs viele, und viel größere und
komplexere.

>>Das muß man aber so machen, sonst kompiliert Delphi das nicht.
Delphi
>>kompiliert aber anstandlos die [0..0] Definition in Windows.pas.
>
>Jetzt tu doch bitte nicht, als ob das andere nicht "anstandslos"
compiliert
>würde.

Ich sage ja: muß man so machen, *sonst* kompiliert Delphi das
nicht. Beachte das Wörtchen "sonst".

>>Genau: Borland macht daraus
>>
>> PEMRPolyDraw = ^TEMRPolyDraw;
>> TEMRPolyDraw = record
>> emr: TEMR;
>> rclBounds: TRect; { Inclusive-inclusive bounds in device
units}
>> cptl: DWORD; { Number of points}
>> aptl: array[0..0] of TPoint; { Array of points}
>> abTypes: array[0..0] of Byte; { Array of point types}
>> end;
>>
>>Wie würdest du das aber mit der [0..SehrViel] Methode beschreiben?
Gar
>>nicht.
>
>Warum nicht? Grundsätzlich muß man sagen, daß die C-Deklartion eine
>Schweinerei erster Güte ist (sogar für C!), und daß der Typ, der das
>verbrochen hat, einen Tag lang an seinen Füßen aufgehängt gehört,
damit er
>sowas in Zukunft unterläßt. Die Startadresse von abTypes kann man
weder in C
>noch in Pascal ohne Rechnerei feststellen. 8-( Die "Struktur", so wie
sie
>aufgeschrieben ist, existiert als solche also gar nicht.

Da gebe ich dir recht. Nur die brachiale Gewalt wäre etwas
übertrieben; da gibt es feinsinnigere Methoden.

Auf solche Strukturen bin übrigens ich in OS/2 auch mehrmals gestoßen.
War auch
eine Qual. Ging aber irgendwie (in Virtual Pascal, damals kompatibel
zu BP7).

>Nur um klarzulegen, ob ich das auch richtig verstanden habe: aptl ist
eine
>beliebig lange Liste von TPoint; und abTypes ist eine darauf folgende
>beliebig lange Liste von Bytes wobei cptl jeweils die aktuelle Länge
der
>Liste angibt. Ich nehme an, daß der Index von aptl mit dem von
apTypes
>korreliert.

So lese ich das auch, ja.

> Wenn man nur 1 Minute nachdenkt, wird man feststellen,
daß es
>dafür - wie immer - eine ganz saubere Pascal-Lösung gibt. Es gibt
eben
>nichts, was man nicht sauber in Pascal lösen könnte 8-):

Also, meinen Schreibtisch kriegst du mit dem besten Pascal (mit oder
ohne MegaPERLs) nicht sauber gelöst ;)

>CONST MaxPoints = MaxMemory DIV SizeOf (TPoint);
>
>TYPE tAptl = ARRAY [0..MaxPoints] OF TPoint;
> pAptl = ^tAptl;


Sollte das nicht [0..MaxPoints - 1] sein? Hatten wir das nicht schon
einmal? Ist aber nicht so wichtig für unser Thema. Also lassen wir das
mal ruhen.

Und stimmt das sonst so? Wäre es nicht sogar korrekter zu schreiben:

const MaxPoints = (MaxMemory - SizeOf(TEMR) - SizeOf(TRect) -
SizeOf(DWord)) div (SizeOf(TPoint) + SizeOf(Byte)); // MaxMemory ist
$7FFFFFFF hier.

Schau dir danach doch z.B. auch einmal EXTLOGPEN,
MENUEX_TEMPLATE_ITEM, MODEMDEVCAPS und MONHSZSTRUCT an.

>TYPE tabTypes = ARRAY [0..MaxPoints] OF BYTE;
> pabTypes = ^tabTypes;
>
>TYPE PEMRPolyDraw = ^TEMRPolyDraw;
> TEMRPolyDraw = record
> emr: TEMR;
> rclBounds: TRect; Inclusive-inclusive bounds in
device
>units}
> cptl: DWORD; { Number of points}
> xxx: BYTE; // Es folgt ein beliebig langer
>Speicherbereich,
> // Miesester C-Code halt..
8-(
> end;

xxx: Byte wurde früher von Borland immer als "xxx: record end;"
deklariert. Ist 0 byte groß und stellt so also nur eine Markierung
(oder
eine Art Label) da.

Du könntest m.E. aptl aber ruhig in dem Record lassen. Aber bei deiner
Methode dann eben als:

aptl: array[0..MaxPoints - 1] of TPoint;


>
>Wie gesagt, die "Struktur" läßt sich ohne Rechnerei nicht auflösen
(auch
>nicht in C):

Nein, wahrlich nicht.

Nur C hat da die besseren Karten.
Ausgehend von der in windows.h deklarierten Struktur:

PEMRPOLYDRAW polydraw = functionsaufruf(blabla);
BYTE *types = (BYTE *)((LPOINT *)&polydraw.aptl + polydraw->cptl);
/* stimmt wirklich! polydraw->cptl wird mit der Größe von LPOINT
skaliert! */

Jetzt kann ich auf aptl mit polydraw->aptl[index] zugreifen und auf
die Types dahinter mit types[index].


>VAR ppd: PemprPolyDraw;
> aptl: pAptl;
> abTypes: pabTypes;
>BEGIN
>ppd:= IrgendeineFunktionDieDieBasisAdresseLiefert;
>aptl:= @ppd^.xxx;

Könntest du ja weglassen, wenn aptl in dem Record definiert wäre.

>abTypes:= POINTER (LONGINT(aptl) + (ppd^.cptl * SizeOf(TPoint)));

Dann wär das: abTypes := Pointer(Longint(@ppd^.aptl) + ppd^.cptl *
SizeOf(TPoint))

Oder:

abTypes := @ppd^.aptl;
Inc(PAptl(abTypes), ppd^.cptl);
// Wird auch skaliert auf Sizeof(PAptl^)!

Das ist m.E. noch etwas safer, da ich keinen
Pointer-Longint-Pointer-Typecast machen muß. Das könnte ja in
irgendeiner Version von Delphi (z.B. D1, mit Segmentierung) Probleme
verursachen. Verschiedene Typen von Zeigern einander zuzuweisen ist da
wohl nicht so schlimm. (Ich weiß wiederum nicht, ob Inc(P, N) in D1
auch so funktioniert. Kann ich jetzt hier nicht ausprobieren).

>Fertisch ist der Balkong. Wenn man mehrere PemprPolyDraw braucht,
fasst man
>die obige Deklaration in einen eigenen Typ:
>
>TYPE MyPemprPolyDraw = RECORD
> ppd:
PEMPRPolyDraw;
> aptl: pAptl;
> abTypes: pabTypes;
> END;


Ja, schön und gut. Das muß der Anwender von Windows.pas machen. Was
macht aber derjenige, der sowas übersetzen muß? Der kann die ganzen
Strukturen auch irgendwie deklarieren, aber wie gibt er weiter, was
damit anzustellen ist? Er muß sich ja an die gelieferten Vorgaben
halten. Da steht eben nix drin von einer MyPEMRPolyDraw-Struktur, und
erst recht nicht, wie ich dann die Zeiger vollkriege. Auch wird deine
MyPEMR... nicht von irgendeine API akzeptiert.

>>Und gerade für solche verzwickte API-Definitionen ist die
>>[0..0]-Methode geeignet.


Für die Deklaration schon geeignet. Für die Anwendung muß man sowieso
mehr oder weniger tricksen. Das geht auch bei dir nicht ganz sauber.

>Denkbar ungeeignet in diesem Falle, denkbar ungeeignet!!! Denn wie
du schon
>schreibst: Ohne Tricks kannst du nicht auf abTypes zugreifen. In
meiner
>Version dagegen schon...

Wie ich sagte: ist Pointer(Longint(aptl) + ...) kein Trick?

Wäre alles einfacher, wenn Zeigererithmetik möglich wäre, wie in C.
Dann wäre der ganze Kram mit für den Zugriff deklarierten Arrays nicht
nötig. Alle Pointer sollten so wie PChar benutzbar sein, aber in der
richtigen Typ-Größe, wie in C. Dann wäre diese Diskussion (also dieser
Thread) wohl nie entstanden.

In C kann ich *Ptr und Ptr[0] genauso äquivalent bernutzen, wie *(Ptr
+ N) und Ptr[N]. In Delphi wäre das also: Ptr^ äquiv. Ptr[0] und (Ptr
+ N)^ äquiv. Ptr[N].

>>... Und
>>für solche Sachen kannst du dich auch nicht mehr auf einen
Range-Check
>>verlassen, da du schon genug tricksen mußt mit Zeigern o.ä.

>Tja. Das es anders, Pascal-konform und sauber mit Rangechecks geht,
habe ich
>gerade aufgezeigt...


Da bin ich anderer Meinung. Du mußt mit Zeigern tricksen und die
kannst du dadurch nicht Bereichsüberprüfen. Allerdings nicht in
Delphi.

Ciao
--
Rudy

Rudy Velthuis

unread,
Mar 12, 1998, 3:00:00 AM3/12/98
to

Nein, wahrlich nicht.

Oder:

In C kann man *Ptr und Ptr[0] genauso äquivalent benutzen, wie *(Ptr


+ N) und Ptr[N]. In Delphi wäre das also: Ptr^ äquiv. Ptr[0] und (Ptr
+ N)^ äquiv. Ptr[N].

>>... Und
>>für solche Sachen kannst du dich auch nicht mehr auf einen
Range-Check
>>verlassen, da du schon genug tricksen mußt mit Zeigern o.ä.

>Tja. Das es anders, Pascal-konform und sauber mit Rangechecks geht,
habe ich
>gerade aufgezeigt...

Da bin ich anderer Meinung. Du mußt mit Zeigern tricksen (über
Longints) und die

Martin

unread,
Mar 13, 1998, 3:00:00 AM3/13/98
to

In article <3505c...@news1.cityweb.de>, rvel...@cww.de says...

> Es spricht für die 0..MaxEtwas methode, daß sie einfacher ist. Das
> gebe ich vollmundig zu. Die 0..0 Methode ist dadurch aber nicht FALSCH
> (nur vielleicht etwas umständlicher). Und das wurde mehrmals (übrigens
> nicht von dir!) behauptet. Dagegen haben Felix (Gunar Scholz) und ich
> Argumente angeführt. Welche Methode man benutzt, ist wohl eher
> persönliche Präferenz.
>

Zum Thema richtig oder falsch habe ich eben nicht die nötige Kompetenz mich zu äussern. Ich
bin aber durchaus bereit die Aussage das die 0..0 Methode nicht mit der Definiton von Pascal
(Standart Pascal) konform geht.
Andererseits muß hier jederzeit klar sein Delphi ist KEIN Standart Pascal, sondern eine von
Borland geformte Abwandlung !

Blieben noch Themen wie Portierbarkeit der Sourcen, aber die kann man auch ohne 0..0 Problem
diskutieren.


Zum Thema persönlich Präferenz:

Ist der programierstil immer :)
Aber ich würde, wenn ich es einem neuen zu erklären hätte, immer die 0..Maxint methode
erklären. Gerade für einen neuen ist die Übersichtlicher.

--

so far Klaus

Martin

unread,
Mar 13, 1998, 3:00:00 AM3/13/98
to

In article <3505c...@news1.cityweb.de>, rvel...@cww.de says...
>
> Es spricht für die 0..MaxEtwas methode, daß sie einfacher ist. Das
> gebe ich vollmundig zu. Die 0..0 Methode ist dadurch aber nicht FALSCH
> (nur vielleicht etwas umständlicher). Und das wurde mehrmals (übrigens
> nicht von dir!) behauptet. Dagegen haben Felix (Gunar Scholz) und ich
> Argumente angeführt. Welche Methode man benutzt, ist wohl eher
> persönliche Präferenz.

In Delphi mag die Methode ja durch Borland als Standart definiert sein. Man beachte eben das
Delphi nur eine Pascal abwandlung ist und kein reines Pascal!!

Wie das in wirklichem Standart Pascal aussieht vermag ich nicht zu sagen.


Ansonsten ist der Programierstil wohl eh immer etwas persönliches.

Einem anfämger würde ich aber immer die 0..Maxint-- Methode empfehlen, da sie gerade für einen
Anfänger übersichtlicher ist.

--
--
Martin

Martin

unread,
Mar 13, 1998, 3:00:00 AM3/13/98
to

In article <3505d...@news1.cityweb.de>, rvel...@cww.de says...

> >Wenn ich Irgendwo (während der Entwicjklung in der IF zeile einen
> Fehler habe, kann das im
> >ersten Falle eher unbemerkt bleiben.
>
>
> Stimmt. Aber wenn du irgendwo einen Fehler hast, kann das sowieso
> lange Zeit unbemerkt bleiben. Die Methode [0..0] muß natürlich sehr
> sorgfältig benutzt werden. Das muß aber die [0..SehrViel]-Methode
> auch. Da darf auch kein Fehler in der Zeile "if (i >= 0) and (i <=
> anz) then" stehen. Soviel sicherer ist die [0..SehrViel]-Methode nun
> wirklich nicht. Es werden aber vom Range-Check natürlich einige
> unwahrscheinliche Werte abgefangen.
>
Mag sein das unwahrscheinlich, aber nicht unmöglich. und daes eher den Eingabeaufwand auch
noch veringert (und man sogar die Überprüfun <0 nicht bedarf) spricht dies eben für 0..max--

Nach der Entwicklungsphase kann der ja sowieso raus (da kommt ja auch $R-), da ich dann davon
ausgehe alle Fehler beseitigt zu haben. Und das Programm ja dann auch rechenzeit optimiert
werden sollte.

> Wie ich schon in einer anderen Mail sagte, würde ich den Zugriff auf
> das Array nur einmal kodieren, in einer eigenen Routine. Die müßte
> dann mit der größten Vorsicht kodiert sein, egal welche Methode für
> die Deklaration verwendet wurde. Aber, wer es nicht schafft, eine
> Zeile wie "if (i >= 0) and (i <= anz) then" zu kodieren, sollte lieber
> Schafe hüten oder Brötchen backen (sehr ehrenwerte Berufe übrigens,
> ich will hier niemanden beleidigen ;).

Du kannst die Zeile ja richtig drin gehabt haben, du brauchst nur beim durchblättern mal ne
flsche Taste zu erwischen, oder aber du hast viele ähnlich Variablennamen, wer würde asich da
nicht mal vertippen.

Und was das nur einmal in einer unterroutine betrifft, das ist schön und gut wenn es von der
Rechenzeit geht. Es gibt aber programme die sehr grosse Datenfluten bewältigen müssen, wenn
dann ein paar Milliarden mal auf das Array zugegriffen wird, merkst du sogar auf einem
schnellern rechner die Zeit für die Aufrufe des Unterprogramm ( nicht nur call und rts,
sondern jedesmal register retten, platz für lokale variablen schaffen und so weiter, jedesmal
nur ein paar millionenstal sekunden. multipliziert mit ein paar milliarden aufrufen, macht ein
paar tausend sekunden.)

--

so far Klaus

Peter Hellinger

unread,
Mar 13, 1998, 3:00:00 AM3/13/98
to

Rudy Velthuis schrieb in Nachricht <35086...@news2.cityweb.de>...

>Nein. Warum feststellen ob? Aus ist aus, auch wenn es schon aus war.
>Und an nur, wenn ich nicht in der Release-Version bin. Es gibt da ja
>nicht soviele Möglichkeiten.


Dann hast du wohl meine Mail mit dem Beispiel mit den beiden Funktionen
nicht so recht gelesen. 8-(
Wenn du brutal wieder einschaltest, obwohl VORHER schon eine Routine
abgeschaaltet hat, bist am Ende, weil du in dem Code in dem du abgeschaltet
hast ein Laufzeitfehler auftritt...

>Klar jetzt? Du bräuchtest ja nicht zu wechseln (toggle), sonder nur
>immer vor dem Arrayzugriff auszuschalten und danach, abhängig von
>RELEASE, wieder einzuschalten oder nicht.


Das funktioniert nicht so wie du dir es vorstellst. Siehe oben.

>>Ich würde eine vernünftige Liste verwenden, und keinen Array... 8-)
>
>[Wir reden aber über offene Arrays (oder Arrays "ohne Grenzen", siehe
>Betreff-Zeile). Ich würde ja auch oft eine TList o.ä. verwenden. Wenn
>ich aber
>auf ein solches Array zugreifen muß, dann nur zentral.]


Offene Arrays sind was anderes als dynamische Arrays. Müssen wir in diese
Diskussion auch wieder einsteigen? 8-(

>Ob vorher als Konstante, oder "on the fly". das kann wirklich viel
>Tipparbeit sein. Probier's mal für:
>
>typedef struct _COMM_CONFIG {
> DWORD dwSize;
> WORD wVersion;
> WORD wReserved;
> DCB dcb;
> DWORD dwProviderSubType;
> DWORD dwProviderOffset;
> DWORD dwProviderSize;
> WCHAR wcProviderData[1];
>} COMMCONFIG, *LPCOMMCONFIG;
>
>Das ist dann noch etwas mehr Tipparbeit:


Verarsche doch die Leute nicht. Diese Struktur hat ein offenes Ende!!!
Deshalb kann DIESE Struktur gar nicht in einem Array stehen, das ist
unmöglich.

>Und davon gibt's in einigen APIs viele, und viel größere und
>komplexere.


Wenn die ein offenes Ende haben, dann können sie keinen Array bilden.
Faktum!

>Und stimmt das sonst so? Wäre es nicht sogar korrekter zu schreiben:
>
>const MaxPoints = (MaxMemory - SizeOf(TEMR) - SizeOf(TRect) -
>SizeOf(DWord)) div (SizeOf(TPoint) + SizeOf(Byte)); // MaxMemory ist
>$7FFFFFFF hier.


Wozu? Warum? Nimm das Maximal mögliche. Du ermittelst ja auch nicht wie
groß dein Programm vielleicht ist, und ziehst den Code von der Maximalgröße
ab.

>Schau dir danach doch z.B. auch einmal EXTLOGPEN,
>MENUEX_TEMPLATE_ITEM, MODEMDEVCAPS und MONHSZSTRUCT an.


Gerne, wenn du mir sagts wo ich das finde. In der Win.api habe ich zB.
TEMPPolyDraw auch nicht gefunden...

> xxx: Byte wurde früher von Borland immer als "xxx: record end;"
>deklariert. Ist 0 byte groß und stellt so also nur eine Markierung
>(oder eine Art Label) da.

Höchst ungewöhnlich, ein leerer Record. Da muß man aber schon Glück haben,
wenn das ein Compiler akzeptiert.

>Du könntest m.E. aptl aber ruhig in dem Record lassen.

Nö, wenn dann mach ich es gleich richtg. Ich habe dann nämlich eine
Konsistenz im Zugriff, dh. auf beide "virtuelle" Arrays wird über Pointer
zugegriffen.

>Könntest du ja weglassen, wenn aptl in dem Record definiert wäre.


Siehe oben, mir ginge es da eher um die Konsistenz.

>Ja, schön und gut. Das muß der Anwender von Windows.pas machen. Was
>macht aber derjenige, der sowas übersetzen muß? Der kann die ganzen
>Strukturen auch irgendwie deklarieren, aber wie gibt er weiter, was
>damit anzustellen ist? Er muß sich ja an die gelieferten Vorgaben
>halten. Da steht eben nix drin von einer MyPEMRPolyDraw-Struktur, und
>erst recht nicht, wie ich dann die Zeiger vollkriege. Auch wird deine
>MyPEMR... nicht von irgendeine API akzeptiert.


Flexibilität ist angesagt! Wenn MS-Programmierer Scheiße bauen - und das
haben sie definitiv in diesem Fall - muß man doch nicht Scheiße
nachprogrammieren?

Und von wegen "wird vom API nicht akzeptiert": Das API liefert ja wohl nur
einen Zeiger auf einen von Windows bereitgestellten Speicher, richtig?
Zeiger sind Zeiger, da interessiert die anhängende Struktur nicht...

>Für die Deklaration schon geeignet. Für die Anwendung muß man sowieso
>mehr oder weniger tricksen. Das geht auch bei dir nicht ganz sauber.


Aber sicher! Das war sauberstes Pascal par excellance! Kein mittel
verwendet, daß nicht aus der Sprache heraus zu einem definierten Ergebnis
führt.

>Wie ich sagte: ist Pointer(Longint(aptl) + ...) kein Trick?


Nein, ein Typecast (definierter Pascal-Sprachumfang), da ich Pointer nicht
einfach addieren kann.

>In C kann ich *Ptr und Ptr[0] genauso äquivalent bernutzen, wie *(Ptr
>+ N) und Ptr[N]. In Delphi wäre das also: Ptr^ äquiv. Ptr[0] und (Ptr
>+ N)^ äquiv. Ptr[N].


Komisch. Vor ettlichen Mails, als ich den Unterschied zwischen den
C-Deklarationen und dem Pascal-Pendant erläuterte hast du genau das
abgestritten... ;-)

>Da bin ich anderer Meinung. Du mußt mit Zeigern tricksen und die
>kannst du dadurch nicht Bereichsüberprüfen.

Zum einhundertausendsten Mal: Bitte begreife endlich, wozu ein Rangecheck da
ist. Er überwacht NICHT den den Zugriff auf Speicher, der NICHT im
Code/Data-Segment des Programmes liegt. Aber er wird dir gewaltig auf die
Finger klopfen, wenn du aus versehen eine 32bit-Variable in einer
16bit-Variable speichern willst.

Helli


Rudy Velthuis

unread,
Mar 13, 1998, 3:00:00 AM3/13/98
to

Peter Hellinger schrieb in Nachricht <6e9fu5$9ou$1...@news.nacamar.de>...


>Und wer sagt, daß ein Rangecheck nicht wichtig ist, hat
>immer noch nicht begriffen wozu ein Rangecheck da ist (nicht um den
Heap zu
>überwachen, sondern um Code/Data zu überwachen).


Richtig, bin ich mit einverstanden.

>Als Hochsprachenprogrammierer interessiert mich es nicht, welchen
>Maschinencode der Compiler erzeugt. Mein Quellcode ist eine
Abstraktion
>einer virtuellen Maschine. Wenn ich zB. die unterschiedlichen
OS-Aufrufe
>weglasse (bzw. in eine plattformabhängige Library packe) müßte es
einem
>Hochsprachen-Quellcode egal sein, welcher konkreter Prozessor
>dahintersteckt, vorausgesetzt ich habe nicht Quellcode geschrieben,
der sich
>auf bestimmte Maschineneigenschaften verläßt. Bestes Beispiel ist C
und
>Unix: Unix gibt es auf einer vielzahl von Hardware-Plattformen, die
>teilweise nicht unterschiedlicher sein können. Dennoch kann man in
der Regel
>ein C-Programm für Unix im Quellcode nehmen und auf jeder beliebigen
>Hardware einfach neu compilieren.


Da hast du schon recht, wenn du möglichst auf Portabilität aus bist.
Nur ich bin da anderer Meinung. Zuerst ist kein Programm so gut, daß
es ewig benutzt wird, ohne geändert zu werden. Zweitens gibt es Delphi
im Moment nur für Wintel und darum finde *ich persönlich* Portabilität
nicht so wichtig, wenn es um Windows- oder andere API-Strukturen geht.
Da würde ich die [0..0]-Methode auch nur einsetzen.

Ich programmiere ja normalwerweise gar nicht so schlampig, wie du es
anfangs angenommen hast. Ich benutze fast immer einen Range-Check und
sogar eine ähnliche Methode wie du in der Deklaration von variablen
Strukturen. Nur kann ich das bei API-Strukturen manchmal nicht. Da muß
ich dann manchmal den [0..0]-Kram verwenden. (Es gibt APIs, z.B. von
RealAudio, die soagr C++-Klassen mit operator overloading (auf
Deutsch: überschriebene Operatoren?) benutzen. Dreh da mal eine
OPascal-Klasse raus. Die Klasse wird nämlich in einigen API-Strukturen
verwendet! Ich benutze im Moment nur Pointer, aber das ist nicht der
Weisheit letzter Schluß.)

Ich bin immer noch davon überzeugt, daß diese Methode völlig gefahrlos
ist, und auch bleiben wird. Darauf verlassen kann ich mich allerdings
nicht, das stimmt. Dann muß ich eben etwas umschreiben. Ist meistens
nicht so problematisch, wie es aussieht. Der Schritt von D1 auf D2 war
nicht ganz einfach, da Win16 und Win32 sehr unterschiedlich sind. An
der VCL hatte sich nicht soviel geändert, was mich gestört hat. Der
Schritt von D2 auf D3 ist einfach.

>>Wenn ich dann in das CPU-Fenster schaue, sehe ich auch tatsächlich,
>>daß das so ist (in allen mir bekannten Delphi-Versionen und in BP7).
>>Wahrscheinlich auch in TP6, TP5.5, TP5, TP4.

>Hast du jemand, der das garantiert? Steht das irgendwo schriftlich in
den
>Borland-Handbüchern?


Siehe oben.

>>Das kann ich mir nicht vorstellen. So dumm stellen die sich
>>ja auch sonst bei Borland nicht an.
>
>Da kann man geteiliter Meinung sein.


Ja. Kann man. Muß man nicht. Aber kann man.

Die VCL ist m.E. sehr gut durchdacht. Sie kapselt besser als MFC oder
OWL, ist aber trotzdem keine allzu dicke (abstrakte) Schicht über das
API. Sie behandelt Ressourcen wie rohe Eier und ist trotzdem leicht zu
benutzen. Sie bietet im Moment auch eine ganze Menge. Schade sind nur
die dazugekauften OCX/ActiveX-Komponenten. Die gehören aber nicht zur
VCL und sind auch nicht von Borland.

Ciao
--
Rudy

Rudy Velthuis

unread,
Mar 13, 1998, 3:00:00 AM3/13/98
to

Peter Hellinger schrieb in Nachricht <6eaktk$r9c$2...@news.nacamar.de>...


>Rudy Velthuis schrieb in Nachricht <35086...@news2.cityweb.de>...
>>Nein. Warum feststellen ob? Aus ist aus, auch wenn es schon aus war.
>>Und an nur, wenn ich nicht in der Release-Version bin. Es gibt da ja
>>nicht soviele Möglichkeiten.
>
>
>Dann hast du wohl meine Mail mit dem Beispiel mit den beiden
Funktionen
>nicht so recht gelesen. 8-(
>Wenn du brutal wieder einschaltest, obwohl VORHER schon eine Routine
>abgeschaaltet hat, bist am Ende, weil du in dem Code in dem du
abgeschaltet
>hast ein Laufzeitfehler auftritt...


Mußte erst mal die Mail zurückholen via DejaNews. Du schreibst:

<QUOTE> <//--------------------->


PROCEDURE Blafasel;
VAR x: ARRAY [0..0] OF BYTE;
i: BYTE;
BEGIN
... irgendwelcher Code zum allozieren etc. ...
i:= 95;
{$R-} // Rangecheck aus sicherstellen
x[i]:= 0:
{$R+} // Rangecheck wieder ein
END;

PROCEDURE FaselFasel;
VAR x: ARRAY [0..0] OF BYTE;
i: BYTE;
BEGIN
... irgendwelcher Code zum allozieren etc. ...
i:= 95;
{$R-} // Rangecheck aus sicherstellen
BlaFasel;
x[i]:= 0:
{$R+} // Rangecheck wieder ein
END;

Der Zugriff auf x in FaselFasel erzeugt einen Laufzeitfehler.

</QUOTE> <//--------------------->

Du machst einen (kapitalen) Denkfehler. Du meinst, weil das {$R+} in
BlaFasel steht, und BlaFasel in FaselFasel aufgerufen wird, der
Range-Check nach dem Ende von BlaFasel (Zur Laufzeit) noch "aktiv"
ist.

Mit {$R+} oder {$R-} wird nichts aktiviert oder deaktiviert
(wenigstens **nicht zur Laufzeit**). {$R+/-} ist lediglich ein
Schalter, der den Compiler dazu bringt, **während der Kompilierung**,
da, wo es notwendig ist, extra Code einzufügen, der Wertebereiche
(nicht: Speicherbereiche) überwacht. Es wird mit {$R+} nicht
irgendeine Überwachungsroutine (zur Laufzeit) gestartet, die aktiv
bleibt, bis sie mit {$R-} wieder ausgeschaltet wird.

Die Schalter selbst gelten nur für den Quelltext und für den Compiler
und sind im Laufzeitmodul nicht vorhanden. Es wird aber in den
Quelltextteilen zwischen {$R+} und {$R-} hier und dort (bei jeder
Zuweisung oder Indizierung oder Parameterübergabe u.ä.) etwas Code
eingefügt, der zur Laufzeit den Bereich überprüft.

Das, was du da annimmst, kann also gar nicht passieren.

>Offene Arrays sind was anderes als dynamische Arrays. Müssen wir in
diese
>Diskussion auch wieder einsteigen? 8-(

Nein. Ich meinte dynamische Arrays variabler (also zur Compile-Time
unbekannter) Länge. War wohl falsch formuliert. Darüber reden wir ja
schon seit Wochen.

>
>>Ob vorher als Konstante, oder "on the fly". das kann wirklich viel
>>Tipparbeit sein. Probier's mal für:
>>
>>typedef struct _COMM_CONFIG {
>> DWORD dwSize;
>> WORD wVersion;
>> WORD wReserved;
>> DCB dcb;
>> DWORD dwProviderSubType;
>> DWORD dwProviderOffset;
>> DWORD dwProviderSize;
>> WCHAR wcProviderData[1];
>>} COMMCONFIG, *LPCOMMCONFIG;
>>
>>Das ist dann noch etwas mehr Tipparbeit:

>Verarsche doch die Leute nicht. Diese Struktur hat ein offenes
Ende!!!
>Deshalb kann DIESE Struktur gar nicht in einem Array stehen, das ist
>unmöglich.

Guten Morgen! Augen auf! Die Struktur *enthält* ein Array
(wcProviderData)! Ich meine nicht ein
array[] **of** TCommConfig, sondern das Array **in** TCommConfig.

>>Und stimmt das sonst so? Wäre es nicht sogar korrekter zu schreiben:
>>
>>const MaxPoints = (MaxMemory - SizeOf(TEMR) - SizeOf(TRect) -
>>SizeOf(DWord)) div (SizeOf(TPoint) + SizeOf(Byte)); // MaxMemory ist
>>$7FFFFFFF hier.
>
>Wozu? Warum? Nimm das Maximal mögliche. Du ermittelst ja auch nicht
wie
>groß dein Programm vielleicht ist, und ziehst den Code von der
Maximalgröße
>ab.
>
>>Schau dir danach doch z.B. auch einmal EXTLOGPEN,
>>MENUEX_TEMPLATE_ITEM, MODEMDEVCAPS und MONHSZSTRUCT an.
>
>Gerne, wenn du mir sagts wo ich das finde. In der Win.api habe ich
zB.
>TEMPPolyDraw auch nicht gefunden...

In meiner Win32.hlp schon. Das ist übrigens EMRPOLYDRAW. das T ist von
Borland (In Windows.pas). Ist die nocj nie aufgefallen, daß Borland
(als Namenskonvention) vor allen Typen ein T einfügt und
GroßkleinSchreibung benutzt? Hast du noch nie eine Struktur aus der
API in win32.hlp aufgesucht? Oder hast du die immer neu definiert?

>> xxx: Byte wurde früher von Borland immer als "xxx: record end;"
>>deklariert. Ist 0 byte groß und stellt so also nur eine Markierung
>>(oder eine Art Label) da.
>
>Höchst ungewöhnlich, ein leerer Record. Da muß man aber schon Glück
haben,
>wenn das ein Compiler akzeptiert.

Delphi akzeptiert das anstandslos (D1/D2/D3). BP(W)7 und TP6 auch. Ist
ja ein Trick von Borland. Sonst könnten die ihre eigenen Bibliotheken
nicht kompilieren.

Delphi benutzt das sogar immer noch, z.B. in TypInfo.pas, OLE2.pas,
und noch einige Units.

>>Ja, schön und gut. Das muß der Anwender von Windows.pas machen. Was
>>macht aber derjenige, der sowas übersetzen muß? Der kann die ganzen
>>Strukturen auch irgendwie deklarieren, aber wie gibt er weiter, was
>>damit anzustellen ist? Er muß sich ja an die gelieferten Vorgaben
>>halten. Da steht eben nix drin von einer MyPEMRPolyDraw-Struktur,
und
>>erst recht nicht, wie ich dann die Zeiger vollkriege. Auch wird
deine
>>MyPEMR... nicht von irgendeine API akzeptiert.
>
>
>Flexibilität ist angesagt! Wenn MS-Programmierer Scheiße bauen - und
das
>haben sie definitiv in diesem Fall - muß man doch nicht Scheiße
>nachprogrammieren?


Ich muß ja öfters (im JEDI-Projekt) C-Header übersetzen nach Delphi
(oder besser: nach Object Pascal). Da muß ich die Sachen bytegetreu
nachbauen in Pascal-Strukturen. Ich benutze die Units ja nicht (nur)
selbst, sondern die werden weitergegeben, getestet, usw.

>Aber sicher! Das war sauberstes Pascal par excellance! Kein mittel
>verwendet, daß nicht aus der Sprache heraus zu einem definierten
Ergebnis
>führt.
>
>>Wie ich sagte: ist Pointer(Longint(aptl) + ...) kein Trick?
>
>
>Nein, ein Typecast (definierter Pascal-Sprachumfang), da ich Pointer
nicht
>einfach addieren kann.

Genau, du behandelst ein Pointer wie ein Longint. Ist das kein Trick
(wenn auch syntaktisch korrekt)? Was, wenn Ponter und Longint auf
einmal (oder wieder) einen total anderen inneren Aufbau haben? Und ist
das denn portabel? Oder in D1 ist ein Pointer ein Selektor:Offset-Paar
und kein Longint. Es ist gefährlich da den typecast Longint(Pointer)
zu machen, dann mit dem Longint was anzustellen und wieder als Pointer
zu interpretieren. Wenn dein Pointer z.B. $0004:$FFF0 ist, und du
addierst 20, dann haben wir: $0005:0004. Dannn gibt's aber böse auf
die Finger von Windows: $0005 ist kein gültiger Selektor. (Nun gibt es
EMRPOLYDRAW nicht in Win16, aber das tut ja nicht zur Sache.)

>
>>In C kann ich *Ptr und Ptr[0] genauso äquivalent bernutzen, wie
*(Ptr
>>+ N) und Ptr[N]. In Delphi wäre das also: Ptr^ äquiv. Ptr[0] und
(Ptr
>>+ N)^ äquiv. Ptr[N].
>
>
>Komisch. Vor ettlichen Mails, als ich den Unterschied zwischen den
>C-Deklarationen und dem Pascal-Pendant erläuterte hast du genau das
>abgestritten... ;-)

Nein, habe ich nicht. Ich kann einen Zeiger und ein Array nicht
verwechseln. Ein Zeiger ist eine Variable, die auf einen
Speicherbreich hinweist (also eine Adresse enthält). Ein Array eine
Folge von Elementen gleichen Typs.

Bei der Speicherung macht das sehr wohl was aus. Bei der Bentuzung im
Quelltext nicht. Das ist genau der gleiche Unterschied wie
"array[0..BlaBla] of Char" und "PChar". Ich kann in Delphi syntaktisch
völlig korrekt schreiben: P^ := 'A'. Als Äquivalent kann ich aber auch
schreiben: P[0] := 'A'. Das ist für den Compiler genau das gleiche.
Trotzdem ist ein PChar kein array[0..Bla] of Char.

Wenn ich also eine Struktur definiere:

TStruct1 = packed record
I: Integer;
C: PChar;
end;

Dann hat eine Variable vom Typ TStruct1 exakt 4 + 4 = 8 Bytes und
enthält eine Zahl und eine Adresse.

TStruct2 = packed record
I: Integer;
C: array[0..255] of Char;
end;

Dann hat eine Variable vom Typ TStruct2 exakt 4 + 256 = 260 Bytes und
enthält eine Zahl und (Platz für) 256 Zeichen.

Das ist *nicht* das gleiche, wie du unschwer erkennen kannst.

Aber ich kann schreiben:

var
S1: TStruct1;
S2: TStruct2;
begin
S1.C := StrNew(S2.C);
for I := 0 to 255 do
S1.C[I] := S2.C[I]; <-- obwohl S1.C ein Zeigertyp ist.
end;

>Zum einhundertausendsten Mal: Bitte begreife endlich, wozu ein
Rangecheck da
>ist. Er überwacht NICHT den den Zugriff auf Speicher, der NICHT im
>Code/Data-Segment des Programmes liegt.

Doch, er überwacht auch ***Werte*** im lokalen Speicher von
Funktionen/Prozeduren, also normalerweise im Stack-Segent oder in
Registern. Er überwacht ***keinen Zugriff***. Windows überwacht
Zugriffe (mit massiver Hilfe der CPU und MMU-Hardware). Zeiger
enthalten keine skalaren Werte, sondern Adressen (siehe oben).

> Aber er wird dir gewaltig
auf die
>Finger klopfen, wenn du aus versehen eine 32bit-Variable in einer
>16bit-Variable speichern willst.

Nicht, wenn die 32bit variable einen *Wert* enthält, der in die 16bit
variable paßt, z.B. 123. Das behauptete ich ja schon immer. Probier es
doch einfach einmal aus:

program Test;

var // Im Data-Segment!
S: ShortInt;
B: Byte;
W: Word;
L: Longint;

begin
{$R+} // <-- !!
L := 123;
S := L;
B := L;
W := L;
B := W;
S := W;
// Sehe dir die Werte von B, W und L an im Watch-Fenster (wie heißt
das in der deutschen Version?)
end.

Das obige Beispiel gibt keine Exception! Es wird auch nichts
überschrieben. Das hat alles zu tun mit der Zuweisungskompatibilität.
Delphi sorgt dafür, daß das richtige in B, und W gespeichert wird. Es
gibt aber eine Exception, wenn ich statt 123 den Wert 1234567 nehme
und dann versuche, L an S zuzuweisen.

Die Bereichsprüfung prüft den momentanen *Wert* einer Variablen, nicht
die möglichen Werte. Also im Grunde genommen ist die Bereichsprüfung
eine Routine (oder Inline-Code), die ähnlich ist wie die folgende:

procedure IntRangeCheck(Variable: Integer; Min, Max: Integer);
begin
if (Variable < Min) oder (Variable > Max) then
raise ERangeError('BlaBla');
end;

Diese Routine wird vom Compiler für jede Zuweisung (etc.) eingefügt
(wenn $R+ für dieses Stück des Quelltextes).

(Natürlich gibt es das auch für Char oder andere ordinalen Werte. Ich
habe Integerwerte lediglich als Vorbild benutzt.)

Also wird was ähnliches wie das folgende kompiliert:

L := 123; // Kein Laufzeit-Range-Check, da 123 konstant.
IntRangeCheck(L, -128, 127);
S := L;
IntRangeCheck(L, 0, 255);
B := L;
IntRangeCheck(L, 0, 65535);
W := L;
IntRangeCheck(W, 0, 255);
B := W;
IntRangeCheck(W, -128, 127);
S := W;

Ich glaube allmählich, daß du ERangeError und EAccessViolation (also
Range-Check und Zugriffsüberwachung)verwechselst. ERangeError ist ein
Hinweis darauf, daß ein Wert nicht zu einem in Pascal definierten Typ
paßt. Ob der Wert physikalisch nicht paßt, oder doch, ist egal. Der
Wert könnte ja physikalisch passen und trotzdem eine ERangeError
auslösen. EAccessViolation ist ein Hinweis darauf, daß auf Speicher
zugegriffen wurde, die dem Programm (dem Task) nicht gehört.

type
MyRange = -3..3;
var
B: MyRange // B kann in einem Speicherbyte gespeichert werden (in 8
Bits).
C: ShortInt;
begin
{$R+}
C := 1;
B := C; <-- kein ERangeError!
C := 12;
B := C; <-- ERangeError! (obwohl 12 in 8 bit paßt).

Siehe auch Online-Hilfe zu $R:

<QUOTE>
This compiler directive enables and disables the generation of
range-checking code

Syntax: {$R+} or {$R-}
{$RANGECHECKS ON} or {$RANGECHECKS OFF}
Default: {$R-}
{$RANGECHECKS OFF}
Scope: Local

On { $R+ }, { $RANGECHECKS ON }

When Range Checking is on, the compiler generates code to check that
array and string subscripts are within bounds, and that assignments to
scalar-type variables do not exceed their defined ***ranges***. Range
checking does not apply to Inc and Dec.
If a check fails, there are the two possible results:

- Run-time errors are translated into exceptions.
- The program halts with a run-time error.

Enabling range-checking slows down your program and makes it larger.
Enable this option during program development and debugging, and then
turn it off when building your final product.

Off { $R- }, { $RANGECHECKS OFF }

When Range Checking is off, no range checking code is generated.

Note: You can also set the Range Checking directive from the Compiler
Options page of the Options|Project dialog box.
</QUOTE>

Range bedeutet: Bereich. Es wird aber nicht ein Speicherbereich
gemeint, sondern ein Wertebereich. Vielleicht hast du das falsch
verstanden (das würde einige deiner Bemerkungen erklären)? Es werden
also keine Adressen überprüft, sondern Werte in Variablen.

Ich könnte sagen: "Bitte begreife das doch endlich". Tu' ich aber
nicht.

--
Rudy Velthuis

-------------------------------------------------
. Gladbeck, NRW Germany
. E-Mail: rvelthuis at cww dot de
-------------------------------------------------
. Join the JEDI Project: www.delphi-jedi.org
-------------------------------------------------

Peter Hellinger

unread,
Mar 13, 1998, 3:00:00 AM3/13/98
to

Rudy Velthuis schrieb in Nachricht <35092...@news2.cityweb.de>...

>Da hast du schon recht, wenn du möglichst auf Portabilität aus bist.
>Nur ich bin da anderer Meinung. Zuerst ist kein Programm so gut, daß
>es ewig benutzt wird, ohne geändert zu werden. Zweitens gibt es Delphi
>im Moment nur für Wintel und darum finde *ich persönlich* Portabilität
>nicht so wichtig, wenn es um Windows- oder andere API-Strukturen geht.


Ich persönlich halte halt Portabilität für das A und O. Ich habe keine Lust
meine erarbeiteten Quellcodes (immerhin kann ich derzeit auf 50 Mb mehr oder
weniger portablen Pascal-Source zu den verschiedensten Themen zurückgreifen)
beim Wechsel einer Maschine neu zu gestalten.

>Ich bin immer noch davon überzeugt, daß diese Methode völlig gefahrlos
>ist, und auch bleiben wird. Darauf verlassen kann ich mich allerdings
>nicht, das stimmt.

Wenns das bloß wäre: Deine Kundschaft kann auf die Nase fallen, und da gibt
es wohl kaum etwas peinlicheres...

>Die VCL ist m.E. sehr gut durchdacht.

Ich bin mir noch nicht so ganz sicher, aber im Augenblick tendiere ich eher
zu einer Pascal-Version der MFC (notfalls selbstgeschrieben). Die VCL ist
mir zu einseitig auf Datenbank-Management ausgelegt.

Helli


Martin

unread,
Mar 14, 1998, 3:00:00 AM3/14/98
to

In article <35071...@news1.cityweb.de>, rvel...@cww.de says...

>
> >Desweiteren kommt hinzu, daß du keinerlei
> >Sicherheit hast, daß der erzeugte Code tatsächlich das tut was er
> soll. Wie
> >gesagt: Das ein konkreter Code von einem konkretem Compiler auf einer
> >konkretem Maschine keinen Fehler erzeugt ist kein Indiz dafür, daß
> kein
> >Fehler existiert. Es ist für einen Programmierer IMMER gefährlich
> Annahmen
> >über die Codeerzeugung oder die Zielmaschine zu machen. Deshalb
> verwendet
> >man ja höhere Programmiersprachen, um von solchen Annahmen befreit zu
> sein.
>
>
> Manchmal muß man mit dieser hohen Programmiersprache in die
> Niederungen eines Windows-API oder ähnliches abtauchen. Da muß man

Gemeint war, daß man nicht ausschliessen kann, das irgendein Compiler der Firma xyz, bei
verwendung vonn 0..0 Code erzeugt der nur auf diese Element 0 zugreift. Unabhängig von dem zu
Laufzeit reservierten Speicher oder dem benutzten Index.

Und da ist es nicht auszudenken was passiert wenn für hunderte Verschiedener Index immer auf
das Element 0 zugegriffen wird.

--
--
Martin

Peter Hellinger

unread,
Mar 14, 1998, 3:00:00 AM3/14/98
to

Rudy Velthuis schrieb in Nachricht <35098...@news1.cityweb.de>...

>Du machst einen (kapitalen) Denkfehler.

Stimmt. Der Compiler folgt ja nicht der Anweisung.


>Guten Morgen! Augen auf! Die Struktur *enthält* ein Array
>(wcProviderData)! Ich meine nicht ein
>array[] **of** TCommConfig, sondern das Array **in** TCommConfig.


Immer noch: JA UND? Wen kümmerts?

>Ist die nocj nie aufgefallen, daß Borland
>(als Namenskonvention) vor allen Typen ein T einfügt und
>GroßkleinSchreibung benutzt?

Jetzt leg doch nicht jeden Buchstaben auf die Goldwaage. Auch EMPPolyDraw
finde ich nicht in meiner Win.api.

>Hast du noch nie eine Struktur aus der
>API in win32.hlp aufgesucht? Oder hast du die immer neu definiert?


Eigentlich nicht. 1. Ich *hasse* Online-Hilfen, besonders die von Delph3i,
die fehlerhaft und zum Teil falsch ist. 2. Ich schau lieber in einen Header
(*.INT) und guck in die entsprechende Original-Doku.

>Ich muß ja öfters (im JEDI-Projekt) C-Header übersetzen nach Delphi
>(oder besser: nach Object Pascal). Da muß ich die Sachen bytegetreu
>nachbauen in Pascal-Strukturen. Ich benutze die Units ja nicht (nur)
>selbst, sondern die werden weitergegeben, getestet, usw.


Und? Habe ich das nicht Bytegetreu nachgebaut?

>Genau, du behandelst ein Pointer wie ein Longint. Ist das kein Trick
>(wenn auch syntaktisch korrekt)?

NEIN, es ist ein Typecast! Das hatten wir doch neulich schon...

>Oder in D1 ist ein Pointer ein Selektor:Offset-Paar
>und kein Longint. Es ist gefährlich da den typecast Longint(Pointer)
>zu machen, dann mit dem Longint was anzustellen und wieder als Pointer
>zu interpretieren.

Ich glaube ich habe seit 1985 keine 16-Bit Maschine mehr programmiert... 8-)

>>Komisch. Vor ettlichen Mails, als ich den Unterschied zwischen den
>>C-Deklarationen und dem Pascal-Pendant erläuterte hast du genau das
>>abgestritten... ;-)
>
>Nein, habe ich nicht.

soll ichs raussuchen?

>Das ist *nicht* das gleiche, wie du unschwer erkennen kannst.


War davon die Rede? IMHO nein...

>Ich glaube allmählich, daß du ERangeError und EAccessViolation (

Ganz sicher nicht.

Rudy Velthuis

unread,
Mar 14, 1998, 3:00:00 AM3/14/98
to

Martin schrieb in Nachricht ...

>In article <3505d...@news1.cityweb.de>, rvel...@cww.de says...
>> >Wenn ich Irgendwo (während der Entwicjklung in der IF zeile einen
>> Fehler habe, kann das im
>> >ersten Falle eher unbemerkt bleiben.
>>
>>
>> Stimmt. Aber wenn du irgendwo einen Fehler hast, kann das sowieso
>> lange Zeit unbemerkt bleiben. Die Methode [0..0] muß natürlich sehr
>> sorgfältig benutzt werden. Das muß aber die [0..SehrViel]-Methode
>> auch. Da darf auch kein Fehler in der Zeile "if (i >= 0) and (i <=
>> anz) then" stehen. Soviel sicherer ist die [0..SehrViel]-Methode
nun
>> wirklich nicht. Es werden aber vom Range-Check natürlich einige
>> unwahrscheinliche Werte abgefangen.
>>
>Mag sein das unwahrscheinlich, aber nicht unmöglich. und daes eher
den Eingabeaufwand auch
>noch veringert (und man sogar die Überprüfun <0 nicht bedarf) spricht
dies eben für 0..max--


Nein, warum? Willst du es auf eine Exception ankommen lassen? Du mußt
auch auf < 0 überprüfen. ich sage übrigens nicht, daß ich die
[0..max]-Methode nicht meistens bevorzuge (siehe all meine anderen
Mails...).

>Nach der Entwicklungsphase kann der ja sowieso raus (da kommt ja auch
$R-), da ich dann davon
>ausgehe alle Fehler beseitigt zu haben. Und das Programm ja dann auch
rechenzeit optimiert
>werden sollte.
>
>> Wie ich schon in einer anderen Mail sagte, würde ich den Zugriff
auf
>> das Array nur einmal kodieren, in einer eigenen Routine. Die müßte
>> dann mit der größten Vorsicht kodiert sein, egal welche Methode für
>> die Deklaration verwendet wurde. Aber, wer es nicht schafft, eine
>> Zeile wie "if (i >= 0) and (i <= anz) then" zu kodieren, sollte
lieber
>> Schafe hüten oder Brötchen backen (sehr ehrenwerte Berufe übrigens,
>> ich will hier niemanden beleidigen ;).
>
>Du kannst die Zeile ja richtig drin gehabt haben, du brauchst nur
beim durchblättern mal ne
>flsche Taste zu erwischen, oder aber du hast viele ähnlich
Variablennamen, wer würde asich da
>nicht mal vertippen.

Es geht nicht ums Vertippen. Beim Vertippen kriegst du ja
normalerweise beim Kompilieren schon Probleme, und nicht erst beim
Testen.

>Und was das nur einmal in einer unterroutine betrifft, das ist schön
und gut wenn es von der
>Rechenzeit geht. Es gibt aber programme die sehr grosse Datenfluten
bewältigen müssen, wenn
>dann ein paar Milliarden mal auf das Array zugegriffen wird, merkst
du sogar auf einem
>schnellern rechner die Zeit für die Aufrufe des Unterprogramm ( nicht
nur call und rts,
>sondern jedesmal register retten, platz für lokale variablen schaffen
und so weiter, jedesmal
>nur ein paar millionenstal sekunden. multipliziert mit ein paar
milliarden aufrufen, macht ein
>paar tausend sekunden.)

1000 Sek = 16 Min 40 Sek. Nur für den Aufruf. Dann noch den Test (den
mußt du immer machen) und den Array-Zugriff. Da bist du aber einige
Stunden beschäftigt. Wenn die Programme übrigens ein paar Milliarden
Byte (= GB) speichern wollen, sollten sie vielleicht kein Array
benutzen, obwohl das das schnellste wär.

Sonst kann ich natürlich auch in der Schleife noch einmal diesen Test
(mit $R-) machen. Ist dann einmal mehr zu kodieren. Es sei dann, du
hast sehr viele, sehr kritische Schleifen. Ist wohl eher nicht der
Fall, oder?

CU l8R, LEg8R. (= Sehe dich später, Alligator)
--
Rudy

Rudy Velthuis

unread,
Mar 14, 1998, 3:00:00 AM3/14/98
to

Martin schrieb in Nachricht ...
>

>In Delphi mag die Methode ja durch Borland als Standart definiert
sein. Man beachte eben das
>Delphi nur eine Pascal abwandlung ist und kein reines Pascal!!
>
>Wie das in wirklichem Standart Pascal aussieht vermag ich nicht zu
sagen.

Borland Pascal hält sich im großen Ganzen am Standard, hat allerdings
viele Erweiterungen implementiert.

>Einem anfämger würde ich aber immer die 0..Maxint-- Methode
empfehlen, da sie gerade für einen
>Anfänger übersichtlicher ist.

Ist eine Deklaration wie [0..$7FFFFFFF div SizeOf(MyStruct) - 1]
wirklich übersichtlicher? Glaube ich nicht.


So far (and yet so near)
So long (and yet so short)
So be it (and yet maybe not)...

Rudy Velthuis

Rudy Velthuis

unread,
Mar 14, 1998, 3:00:00 AM3/14/98
to

Martin schrieb in Nachricht ...

>> Manchmal muß man mit dieser hohen Programmiersprache in die
>> Niederungen eines Windows-API oder ähnliches abtauchen. Da muß man
>
>Gemeint war, daß man nicht ausschliessen kann, das irgendein Compiler
der Firma xyz, bei
>verwendung vonn 0..0 Code erzeugt der nur auf diese Element 0
zugreift. Unabhängig von dem zu
>Laufzeit reservierten Speicher oder dem benutzten Index.
>
>Und da ist es nicht auszudenken was passiert wenn für hunderte
Verschiedener Index immer auf
>das Element 0 zugegriffen wird.


Ich bin aber gar nicht interessiert in einen Compiler der Firma XYZ.
Also was soll das? Portabilität interessiert mich insofern nicht, als
daß die Benutzung von Wintel APIs sowieso nicht sehr portabel ist. Bei
anderen Strukturen benutze ich ja die [0..0]-Methode gar nicht (obwohl
ich auch das könnte).

Rudy


Rudy Velthuis

unread,
Mar 14, 1998, 3:00:00 AM3/14/98
to

Peter Hellinger schrieb in Nachricht <6edh8o$90p$1...@news.nacamar.de>...


>Rudy Velthuis schrieb in Nachricht <35092...@news2.cityweb.de>...
>>Da hast du schon recht, wenn du möglichst auf Portabilität aus bist.
>>Nur ich bin da anderer Meinung. Zuerst ist kein Programm so gut, daß
>>es ewig benutzt wird, ohne geändert zu werden. Zweitens gibt es
Delphi
>>im Moment nur für Wintel und darum finde *ich persönlich*
Portabilität
>>nicht so wichtig, wenn es um Windows- oder andere API-Strukturen
geht.
>
>
>Ich persönlich halte halt Portabilität für das A und O. Ich habe
keine Lust
>meine erarbeiteten Quellcodes (immerhin kann ich derzeit auf 50 Mb
mehr oder
>weniger portablen Pascal-Source zu den verschiedensten Themen
zurückgreifen)
>beim Wechsel einer Maschine neu zu gestalten.


Ist dein gutes Recht. Nur: wie portabel ist Code, der die VCL und das
Windows-API gleichzeitig benutzt?

Portabilität ist für allgemeine, betriebbsystemunabhängige Routinen
kein Problem, das erfordert nur etwas mehr nachdenken und etwas mehr
Disziplin. Es wird bei hardware- und betriebssystemabhängige Routinen
aber schon schwieriger, wenn nicht unmöglich.

Ich würde eine Mathe-Bibliothek, oder eine ISAM-Bibliothek, usw.,
absolut portabel gestalten. Nur z.B. eine Routine, die die sovielte
Scanline eines Bitmaps liest unter Windows, oder ein Programm, daß
Sound ausgeben und mischen muß unter Windows, sind da nicht so
portabel. Die würde ich auf einem anderen System (OS/2, Linux, Mac)
völlig neu schreiben.

Ich bevorzuge die Methode, die z.B. POV-Ray, ein Raytracer, einschlägt
(allerdings in C): Für die ganze Mathe des Bildes (Reflektion, Farben,
Schatten, Oberflächen, etc.) wird portabler Code geschrieben. Für die
Ausgabe (auf dem Schirm oder in Datei) und das User-Interface
(Fenster, usw.) wird für jedes System anderer Code geschrieben.

>>Ich bin immer noch davon überzeugt, daß diese Methode völlig
gefahrlos
>>ist, und auch bleiben wird. Darauf verlassen kann ich mich
allerdings
>>nicht, das stimmt.

>Wenns das bloß wäre: Deine Kundschaft kann auf die Nase fallen, und
da gibt
>es wohl kaum etwas peinlicheres...

Nein, ich meinte: Ich bin mir sicher, das es jetzt gefahrlos ist. Ich
kann mich nur nicht darauf verlassen, daß es so bleibt. Wenn nicht,
werde ich das schnell genug merken (hier, nicht beim Kunden).

Rudy

Rudy Velthuis

unread,
Mar 14, 1998, 3:00:00 AM3/14/98
to

Peter Hellinger schrieb in Nachricht <6edjs5$he9$4...@news.nacamar.de>...
>Rudy Velthuis schrieb in Nachricht <35098...@news1.cityweb.de>...


>>Du machst einen (kapitalen) Denkfehler.
>

>Stimmt. Der Compiler folgt ja nicht der Anweisung.
>
>

>>Guten Morgen! Augen auf! Die Struktur *enthält* ein Array
>>(wcProviderData)! Ich meine nicht ein
>>array[] **of** TCommConfig, sondern das Array **in** TCommConfig.
>
>

>Immer noch: JA UND? Wen kümmerts?

Hast du keine bessere Antwort? Wie würdest du das übersetzen?

>
>>Ist die nocj nie aufgefallen, daß Borland
>>(als Namenskonvention) vor allen Typen ein T einfügt und
>>GroßkleinSchreibung benutzt?
>

>Jetzt leg doch nicht jeden Buchstaben auf die Goldwaage. Auch
EMPPolyDraw
>finde ich nicht in meiner Win.api.

Echt nicht? Dann hast du eine andere win32.hlp als ich.
Heißt EMRPolyDraw (EMR = enhanced metafile record). Siehe enhanced
Metafile Records o.ä. EMRs sind afaik schon Bestandteil vom
Original-Windows 95.
Muß bei D3 dabei sein.

>>Hast du noch nie eine Struktur aus der
>>API in win32.hlp aufgesucht? Oder hast du die immer neu definiert?
>

>Eigentlich nicht. 1. Ich *hasse* Online-Hilfen, besonders die von
Delph3i,
>die fehlerhaft und zum Teil falsch ist.

Die Win32.hlp ist von M$. Die ist unverändert übernommen. Allerdings
nicht in der normalen Delphi-Hilfe eingebunden. Muß separat aufgerufen
werden (da gibt es einen Toolbar-Schalter für, glaube ich, den man in
die Toolbar einfügen könnte
).

2. Ich schau lieber in einen
Header
>(*.INT) und guck in die entsprechende Original-Doku.

Hast du eine Original-Doku zum ganzen WinAPI? Woher bitte? Hätte ich
auch gerne.

>>Ich muß ja öfters (im JEDI-Projekt) C-Header übersetzen nach Delphi
>>(oder besser: nach Object Pascal). Da muß ich die Sachen bytegetreu
>>nachbauen in Pascal-Strukturen. Ich benutze die Units ja nicht (nur)
>>selbst, sondern die werden weitergegeben, getestet, usw.
>

>Und? Habe ich das nicht Bytegetreu nachgebaut?

Nein, du hast aus einer Struktur mehrere gemacht. Das paßt nicht zur
deklarierten Struktur. Siehe oben. Der Benutzer der Unit kann dann
nicht
Struktur.Element benutzen, sodern muß MyStruktur.AnderesElement
benutzen. Das weiß er aber nicht. Problem ist: ich muß die Struktur
konform der Doku halten. Ich kann z.B. die win32.hlp nicht eben neu
schreiben (und darf es nicht einmal). Daß der Benutzer dann selbst
etwas kodieren muß, wie du beschrieben hast, ist mir klar.

Nun, die direkte Übersetzung von RGBQUAD bla[1] ist nun einmal bla:
array[0..0] of TRGBQUAD. Nur das erwartet der Benutzer.
array[0..MaxEtwas] of TRGBQUAD ist dann schon anders. Wenn irgendein
Dösbaddel nun z.B. SizeOf(TBITMAPINFO) abfragt, wird er sich wundern,
wenn er dann statt einige Bytes auf einmal fast 2GB raus kriegt. Oder
wenn er eins alloziert, fällt er noch mehr auf die Nase.

Wenn ich also einen richtigen TBitmapInfo brauche, kann ich das so
machen:

GetMem(P, SizeOf(TBitmapInfo) + (n-1) * Sizeof(TRGBQUAD));

Wenn ich nun deine Deklaration verwendet wurde, müßte ich das so
machen.

GetMem(P, SizeOf(TBitmapInfoHeader) + N * SizeOf(TRGBQUAD));

Das geht ja noch, weil vor dem Array nur ein TBitmapInfoHeader steht.
Wenn aber vor dem Array in der Struktur viele viele verschiedene
Felder stehen, ist das schon etwas umständlicher.

Bei EXTLOGPEN (Windows.pas) ist das etwas mehr Arbeit:

TExtLogPen = packed record
elpPenStyle: DWORD;
elpWidth: DWORD;
elpBrushStyle: UINT;
elpColor: COLORREF;
elpHatch: Longint;
elpNumEntries: DWORD;
elpStyleEntry: array[0..0] of DWORD;
end;

Gibt dann:

Getmem(Pen, Sizeof(TExtLogPen) + (NumEntries - 1) * DWORD);

Bei deiner Deklaration aber:

GetMem(P, Sizeof(UINT) + Sizeof(COLORREF) + SizeOf(Longint) + (N +
3) * Sizeof(DWORD));

Nicht vergessen: eigene Deklarationen, wie MyExtLogPen ohne das Feld
elpStyleEntry sind nicht dokumentiert, und kann man daher nicht
einfach weitergeben oder benutzen. Ist auch noch umständlicher, weil
du das als Benutzer machen müßtest.

Also ich finde, daß man bei solchen Übersetzungen nicht mehr
hineinübersetzen darf, als da steht. Wenn der C-Header ein array[1]
definiert, schreibe ich eine [0..0]. Sonst ist das nicht eine genaue
Übersetzung. Daß das dann für den Benutzer die Konsequenz hat, daß er
$R- benutzen muß,ist zwar bedauerlich, aber ich kann das nicht ändern.
Die Definition ist von z.B. Microsoft, nicht von mir.

Borland denkt da anscheinden genau so. Oder noch radikaler, weil sie
sogar [0..0] in Unit System benutzen.

>>Genau, du behandelst ein Pointer wie ein Longint. Ist das kein Trick
>>(wenn auch syntaktisch korrekt)?
>

>NEIN, es ist ein Typecast! Das hatten wir doch neulich schon...

Es ist ein Trick. Du addierst einen Zeiger mit Hilfe eines Typecast.
Nicht der Typecast selbst ist der Trick, sondern, daß du den Zeiger
wie ein Longint behandelst und damit addierst. Das ist m.E.
gefährlicher als der [0..0]-Trick (ohne $R)! Es ist nicht richtig und
absolut
nicht portabel. Aber es funktioniert hier "zufälliger"weise (und wir
wissen ja beide:
ohne Probleme).

Im Grunde genommen machst du hier etwas, was du mir vorwirfst und bei
mir falsch nennst. Wo ist z.B. dokumentiert, daß man zu Zeiger so
Offsets addieren darf? Nirgendwo! Du gehst von dir bekannten Interna
aus. Du nimmst an, daß ein Zeiger eine lineare Adresse enthält.
FALSCH! In D1 ist das z.B. nicht so! Und wer weiß, ob Intel nicht
irgendwann wieder eine neue Variante des PII herausbringt, die wieder
Segmente benutzt (weil an Adreßleitungen gespart wurde, oder mehr als
4GB mit 32bit-Registern angesprochen werden müssen).

Wie du inetwa schon einmal sagtest: "Wer garantiert mir, daß das auf
eine andere
Maschine genauso funktioniert?"

Was lernen wir daraus? Wer API- oder Hardware-Strukturen benutzt, muß
manchmal zu Tricks greifen, die die Sprache so nicht vorsieht. Es ist
z.B. auch in (16bit) D1 möglich, Datenbereiche größer 64k zu
allozieren (WAVs, Bitmaps). Nur beim
Zugriff mußt du auch Tricks benutzen (32bit-Register in D1), das geht
nur noch zuverlässig in Assembler. Aber dann auch ganz gut.
Funktioniert dann wieder nicht auf 286er. Kann ich mit leben.

Auch gibt es Tricks, die nur unter Win95 (oder gar unter DOS) möglich
sind, und nicht unter
NT. Dann läuft das Programm eben nicht unter NT. Wenn es z.B. ein
Spiel ist, nennt man es dann "Ballermann 6.0 for Windows 95" oder so.
Portablität ist schön, aber eben nicht alles. (Und unterschätze Spiele
nicht. Sind schwer zu programmieren und sind der Hauptantrieb für die
Grafikkarten- und Soundkarten-Entwickler. 3D ist doch für Spiele
entwickelt, weil das der größte Markt ist.)

>Ich glaube ich habe seit 1985 keine 16-Bit Maschine mehr
programmiert... 8-)

Und wer das glaubt, wird selig.

>>>Komisch. Vor ettlichen Mails, als ich den Unterschied zwischen den
>>>C-Deklarationen und dem Pascal-Pendant erläuterte hast du genau das
>>>abgestritten... ;-)
>>
>>Nein, habe ich nicht.
>

>soll ichs raussuchen?

Ich bitte drum. Ich habe die Mails (leider) nicht mehr. Ich hatte
große Probleme mit meiner ISDN-Karte und M$ Outlook hat danach alle
Mails gelöscht. Ich weiß ungefähr noch, welche du meinst. Ich habe nie
behauptet, Zeiger und Arrays sind das gleiche.

>>Das ist *nicht* das gleiche, wie du unschwer erkennen kannst.
>
>

>War davon die Rede? IMHO nein...

IMHO schon.

Du hast in deiner Struktur Zeiger gespeichert, wo im Original ein
array[1] (in C syntax) war. Man kann in einer im API dokumentierten
Struktur nicht einfach was einfügen oder ändern. Man muß die
Original-Struktur weitergeben, so gut und so schlecht es geht. Man
kann auch keine neuen (Hilfs-)Strukturen einfügen.

>>Ich glaube allmählich, daß du ERangeError und EAccessViolation (
>

>Ganz sicher nicht.


Das freut mich.

Rudy

Peter Hellinger

unread,
Mar 14, 1998, 3:00:00 AM3/14/98
to

Rudy Velthuis schrieb in Nachricht <350a6...@news2.cityweb.de>...

>Ist dein gutes Recht. Nur: wie portabel ist Code, der die VCL und das
>Windows-API gleichzeitig benutzt?


Zunächst mal sollte man zwischen Oberfläche und Programm unterscheiden. Eine
saubere DBase-Datenbank-Schnittstelle kann ich unter jeder Plattform
programmieren, unabhängig von der Oberfläche. Leider geht das schon mal
nicht mit der BDE...

>Portabilität ist für allgemeine, betriebbsystemunabhängige Routinen
>kein Problem, das erfordert nur etwas mehr nachdenken und etwas mehr
>Disziplin. Es wird bei hardware- und betriebssystemabhängige Routinen
>aber schon schwieriger, wenn nicht unmöglich.


Ach was! Dafür hat man ein Modul, welches die wichtigsten Sachen kapselt.
Und dann muß nur das Modul angepasst, bzw. ausgetauscht werden.

>Ich würde eine Mathe-Bibliothek, oder eine ISAM-Bibliothek, usw.,
>absolut portabel gestalten. Nur z.B. eine Routine, die die sovielte
>Scanline eines Bitmaps liest unter Windows,

Bitmaps sind aber keine Eigenschaft von Windows, die finde ich unter jedem
System. Akso kann ich mir eine Lib bauen, die auch Betriebssystemunabhängig
funktioniert.

>oder ein Programm, daß
>Sound ausgeben und mischen muß unter Windows, sind da nicht so
>portabel. Die würde ich auf einem anderen System (OS/2, Linux, Mac)
>völlig neu schreiben.


Selbst schuld... 8-)

>Ich bevorzuge die Methode, die z.B. POV-Ray, ein Raytracer, einschlägt
>(allerdings in C): Für die ganze Mathe des Bildes (Reflektion, Farben,
>Schatten, Oberflächen, etc.) wird portabler Code geschrieben. Für die
>Ausgabe (auf dem Schirm oder in Datei) und das User-Interface
>(Fenster, usw.) wird für jedes System anderer Code geschrieben.


Das hat ja nicht gerade POV-Ray erfunden. Sowas gibts seit Knuths Zeiten und
nennt sich TeX...

>Nein, ich meinte: Ich bin mir sicher, das es jetzt gefahrlos ist. Ich
>kann mich nur nicht darauf verlassen, daß es so bleibt. Wenn nicht,
>werde ich das schnell genug merken (hier, nicht beim Kunden).


Wie gesagt. Ich hoffe niemals in die Verlegenheit kommen zu müssen eines
deiner Programme benutzen zu müssen.

Helli


Peter Hellinger

unread,
Mar 14, 1998, 3:00:00 AM3/14/98
to

Rudy Velthuis schrieb in Nachricht <350a7...@news2.cityweb.de>...


>Hast du keine bessere Antwort? Wie würdest du das übersetzen?

Irgendwie werde ich das Gefühl nicht los, daß du mir ständig deine
Problemfälle vorsetzt, nur um von mir eine saubere Pascal-Deklraration zu
bekommen...

>Echt nicht?

Nein. Ich finds aber in der Hilfe von C++

>Dann hast du eine andere win32.hlp als ich.

Liegt vielleicht an dem "Standard" auf der Delphi-Verpackung.

>Die Win32.hlp ist von M$. Die ist unverändert übernommen.

Sie unterscheidet sich ganz offensichtlich von der, die VC++ beiliegt.

>Hast du eine Original-Doku zum ganzen WinAPI? Woher bitte? Hätte ich
>auch gerne.

Diverse Microsoft Press Bücher und die Win95/NT API-Bible von Richard Simon
(in 3 Bänden). Ein Blick in den Quellcode sagt mir oft mehr als eine
seitenlange Online-Hilfe.

>Nein, du hast aus einer Struktur mehrere gemacht. Das paßt nicht zur
>deklarierten Struktur. Siehe oben.

Und ob das gepaßt hat. Probiers aus!

>Der Benutzer der Unit kann dann nicht Struktur.Element benutzen,
>sodern muß MyStruktur.AnderesElement benutzen.

Kriegt der Benutzer der Unit nun den C-Header oder das Pascal-Interface?

>Das weiß er aber nicht. Problem ist: ich muß die Struktur
>konform der Doku halten. Ich kann z.B. die win32.hlp nicht eben neu
>schreiben (und darf es nicht einmal). Daß der Benutzer dann selbst
>etwas kodieren muß, wie du beschrieben hast, ist mir klar.

Du argumentierst am Problem vorbei (nicht zum erstenmal übrigens).

>Nun, die direkte Übersetzung von RGBQUAD bla[1] ist nun einmal bla:
>array[0..0] of TRGBQUAD. Nur das erwartet der Benutzer.
>array[0..MaxEtwas] of TRGBQUAD ist dann schon anders. Wenn irgendein
>Dösbaddel nun z.B. SizeOf(TBITMAPINFO) abfragt, wird er sich wundern,
>wenn er dann statt einige Bytes auf einmal fast 2GB raus kriegt. Oder
>wenn er eins alloziert, fällt er noch mehr auf die Nase.

Wenn er das tut, geschiehts ihm recht. Wenn er hier mit SizeOf operiert, ist
es immer Falsch, egal wie der Array deklariert wurde.

>GetMem(P, SizeOf(TBitmapInfo) + (n-1) * Sizeof(TRGBQUAD));

Woher hast du denn n?

>Bei EXTLOGPEN (Windows.pas) ist das etwas mehr Arbeit:
>
> TExtLogPen = packed record
> elpPenStyle: DWORD;
> elpWidth: DWORD;
> elpBrushStyle: UINT;
> elpColor: COLORREF;
> elpHatch: Longint;
> elpNumEntries: DWORD;
> elpStyleEntry: array[0..0] of DWORD;
> end;
>
>Gibt dann:
>
> Getmem(Pen, Sizeof(TExtLogPen) + (NumEntries - 1) * DWORD);
>
>Bei deiner Deklaration aber:
>
> GetMem(P, Sizeof(UINT) + Sizeof(COLORREF) + SizeOf(Longint) + (N +
>3) * Sizeof(DWORD));

Warum machst du das so umständlich?

>Nicht vergessen: eigene Deklarationen, wie MyExtLogPen ohne das Feld
>elpStyleEntry sind nicht dokumentiert, und kann man daher nicht
>einfach weitergeben oder benutzen. Ist auch noch umständlicher, weil
>du das als Benutzer machen müßtest.

??? Wenn ich an einem Projekt arbeite, entscheide ICH was dokumentiert ist.
Oder etwa nicht?

>Also ich finde, daß man bei solchen Übersetzungen nicht mehr
>hineinübersetzen darf, als da steht. Wenn der C-Header ein array[1]
>definiert, schreibe ich eine [0..0].

Sehe ich absolut anders. Falsche Programmierung fortzusetzen ist ja wohl der
größte Krampf den man machen kann.

>>NEIN, es ist ein Typecast! Das hatten wir doch neulich schon...
>
>Es ist ein Trick.

ES IST EIN TYPECAST. Er wäre nicht notwendig, wenn Pascal Pointer addieren
könnte (dann müsste ich aber aus einem Longint einen Pointer casten).

>Das ist m.E. gefährlicher als der [0..0]-Trick (ohne $R)! Es ist nicht
>richtig und absolut nicht portabel.

Wie kommst du denn auf das schmale Brett?

>Im Grunde genommen machst du hier etwas, was du mir vorwirfst und bei
>mir falsch nennst. Wo ist z.B. dokumentiert, daß man zu Zeiger so
>Offsets addieren darf? Nirgendwo!

Hä? Bin ich etwa im falschen Film? Natürlich ist das dokumentiert! Kann
Pascal etwas dafür, daß 16-Bit Intels nicht durchgängig adressieren können?

>Du gehst von dir bekannten Interna aus. Du nimmst an, daß ein Zeiger eine
>lineare Adresse enthält. FALSCH! In D1 ist das z.B. nicht so!

FALSCH! Es ist nicht in D1 so, sondern es betrifft 16Bit-Intel-Architektur
unter DOS/Win3x.

>Wie du inetwa schon einmal sagtest: "Wer garantiert mir, daß das auf
>eine andere Maschine genauso funktioniert?"

Pointer-Addition? Funktioniert auf jeder Maschine, ausser auf solchen, die
16bit-Intel-Architektur haben. Auf solche "Maschinen" programmiere ich
nicht.

>Was lernen wir daraus?

Das du wieder einmal verschiedene Dinge in einen Topf wirfst, ohne genau
darüber bescheid zu wissen.

>>Ich glaube ich habe seit 1985 keine 16-Bit Maschine mehr
>programmiert... 8-)
>
>Und wer das glaubt, wird selig.

Worauf ich programmiert habe und programmiere werde ich wohl besser wissen
als du. MacIntosh und AtariST/TT sind reinrassige 32-Bitter und beide gabs
schon lange bevor Intel gelernt hat bis 32 zu zählen. Auch Unix-Machinen
hatten schon immer einen linearen Adressraum von 4Gb. Nur weils für Intel
erst seit 1995 ein 32-Bit Betriebssystem (von MS) gibt, heißt das noch lange
nicht, daß da erst 32Bit-Programmierung erfunden wurde. Bis auf zwei oder
drei Q&D-Hacks (< 30 kb) für den Hausgebrauch gibts von mir nichts, was auf
16Bit-Intels läuft. Dagegen gibts Megabyteweise Zeugs von mir, was auf
Macs, Ataris und 32Bit-Intel läuft. Vor 1985 hatte ich eine 8-bit-Maschine
mit
CP/M, und noch davor hatte ich schon einen 16-Bitter (mit 8 Bit-Adressbus).

>Du hast in deiner Struktur Zeiger gespeichert, wo im Original ein
>array[1] (in C syntax) war.

NEIN, DEFINITIV NICHT! Langsam werd´ich sauer, weil du meine Mails offenbar
nur halb liest, und dann etwas hineininterpretierst, was sich so nicht
gesagt habe. Ich habe in der Struktur NIRGENDWO Zeiger GESPEICHERT, wo
etwas anders stehen sollte. Ich habe Zeiger benutzt um auf das zu zeigen,
was ich in der Struktur bewußt unterschlagen habe. Das ist ein ganz
gewaltiger Unterschied.

>Man kann in einer im API dokumentierten
>Struktur nicht einfach was einfügen

Das habe ich auch nicht.

>oder ändern.

Iabe etwas weggelassen. Genauso wie der, der ein ARRAY [0..0] anhängt. Nur
sauber.

>Man muß die
>Original-Struktur weitergeben, so gut und so schlecht es geht. Man
>kann auch keine neuen (Hilfs-)Strukturen einfügen.

Doch. Kann und muß man wenn die Vorlage Scheiße ist. und das ist sie in dem
Falle ganz besonders

Wenn MS nicht Idioten für solche Sachen beschäftigt hätte, müsste diese
Struktur so aussehen:

typedef struct tagEMRPOLYDRAW
{
EMR emr;
RECTL rclBounds;
DWORD cptl;

POINTL *aptl;
BYTE *abTypes;
} EMRPOLYDRAW, *PEMRPOLYDRAW;

Speicher allozierst du dann mit ...->aptl =
calloc(...->cptl,sizeof(POINTL)), wobei ... für einen Zeiger auf
EMRPOLYDRAW darstellt, also zB. PEMRPLOYDRAW p. Bitte beachten,
daß vor dem p kein * steht, weil bei der Typdeklaration schon ein Zeiger
deklariert wurde (im Gegensatz zu EMRPOLYDRAW, was eine normale
Struktur ist, da bräuchte man das * Nach dem calloc (c steht übrigens für
clear=löschen) greifst du mit p->aptl[x] darauf zu, wobei x zwischen 0 und
cptl (nicht eingeschlossen) liegt.

So macht man das in C. Und in Pascal ist es ein leichtes sowas
nachzuprogrammieren, indem man die Zeiger als Zeiger auf Array [0..max]
deklariert. Lieder bestreitest du sowohl die saubere C als auch die saubere
Pascal-Lösung... 8-(

Helli

It is loading more messages.
0 new messages