Erstes Zeichen im String bei [0]

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Mathias
Beiträge: 6911
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Erstes Zeichen im String bei [0]

Beitrag von Mathias »

Ich habe gerade folgendes in der Maillist gefunden.
Dieser Code funktioniert zumindest mit FPC 3.3.

Code: Alles auswählen

program Project1;

  {$zerobasedstrings on}

var
  s: string = 'Hello World';
  i: integer;

begin
  for i := 0 to Length(s) - 1 do begin
    Write(s[i]);
  end;
  WriteLn();
end
Was ich mir aber dabei vorstellen kann, das da ein Chaos vorprogrammiert ist, obwohl mir es auch sympatisch wäre, wen Strings bei 0 anfangen, wie jede andere Array.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
theo
Beiträge: 10870
Registriert: Mo 11. Sep 2006, 19:01

Re: Erstes Zeichen im String bei [0]

Beitrag von theo »

Das ist ein Delphi Kompatibilitätsding und auch nicht neu (Seit 3.0 oder so).
Das löst anscheinend ein Delphi Problem.
https://docwiki.embarcadero.com/RADStud ... s_(Delphi)

MMn vergisst man das besser gleich wieder.

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 359
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Erstes Zeichen im String bei [0]

Beitrag von Jorg3000 »

Moin!
Die Compiler-Direktive {$zerobasedstrings on} kannte ich noch gar nicht.

Der Typ String wurde 1983 von Turbo Pascal eingeführt, damals zunächst als ShortString, wobei das erste Byte das Längenbyte ist (zuvor Array of Char ohne flexible Länge).
Das heißt, dass der Zeichen-Zugriff im String-Typ bisher immer Index-1-basiert war - und das jetzt seit über 40 Jahren!

Somit denke ich auch, dass deine Befürchtung berechtigt ist, auch wenn ich selbst kein "Chaos" befürchte. Denn die Direktive bezieht sich nur darauf, wie eine einzelne Unit die Zeichen adressiert. Wenn der String an eine Funktion in einer anderen Unit übergeben wird, die diese nicht Direktive nicht nutzt, so wird dort derselbe String-Inhalt herkömmlich adressiert, ohne dass es Probleme gibt.

Vielleicht sollte der Programmierer einer Unit, worin er zerobasedstrings verwendet, alle String-Zugriffe vorsichtshalber mit // zero-based o.ä. kommentieren, damit andere Leser nicht irritiert sind. Denn die Compiler-Direktive im Unit-Header wird man wohl leicht übersehen. Insbesondere bei Funktionen wie Insert() und Copy() wird's spannend - ist es eine externe Funktion, die 1-basiert ist, oder eine interne Funktion, für welche die lokale Direktive gilt? Woran kann man das erkennen?

Da ich schon sehr lange in Pascal programmiere, werde ich die neue Direktive vermutlich nicht einsetzen, obwohl ich für andere Sprachen immer umdenken muss. Trotzdem hat es sich in meinen alten Schädel eingebrannt, dass es bei Pascal 1-basiert ist. Übrigens ebenso bei den alten Programmiersprachen Fortran und COBOL, denn bei COBOL sind sogar alle Arrays generell 1-basiert.

Vielleicht sehen junge Programmierer das anders (sofern es die im Pascal-Bereich überhaupt gibt) und steigen gerne zero-based ein.
Grüße, Jörg

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

Re: Erstes Zeichen im String bei [0]

Beitrag von Warf »

Die Direktive beeinflusst einfach nur die direkten Zugriffe auf die chars in der aktuellen unit. Es beeinflusst nicht das Verhalten von Funktionen wie Copy, Pos, etc.
Dafür gibt es allerdings die String Helper Funktionen, die sind alle 0 basiert. D.h. mit dem Compiler switch und den Helper Funktionen, kann man problemlos mit 0 basierten string Indizes ohne Chaos arbeiten.
Mach das schon seit Jahren und ist typischerweise eine der ersten switches die ich setze

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

Re: Erstes Zeichen im String bei [0]

Beitrag von Mathias »

Der Typ String wurde 1983 von Turbo Pascal eingeführt, damals zunächst als ShortString, wobei das erste Byte das Längenbyte ist (zuvor Array of Char ohne flexible Länge).
Das heißt, dass der Zeichen-Zugriff im String-Typ bisher immer Index-1-basiert war - und das jetzt seit über 40 Jahren!
Genau so ist es. Das mit dem beginnenden [0] hätte man mit dem AnsiString einführen müssen, als auch die dynamischen Array raus kamen.
Jetzt verursacht die nur noch ein Chaos. Einzig was die vielleicht umgehen könnte, wäre ein neuer StringTyp. ODer man arbeit einfach mit "array of char".

Was mir noch ein sympatisches Features wäre, wen ein statisches array nicht immer ein ".." bräuchte, wen es mit 0 beginnt.

Erste Variante wäre doch sympatischer.

Code: Alles auswählen

var
  a: array[8] of char;
var
  a: array[0..7] of char;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: Erstes Zeichen im String bei [0]

Beitrag von m.fuchs »

Mathias hat geschrieben: Mo 7. Apr 2025, 13:08 Was mir noch ein sympatisches Features wäre, wen ein statisches array nicht immer ein ".." bräuchte, wen es mit 0 beginnt.
Du willst mehr Missverständlichkeit um dadurch drei Zeichen zu sparen... :roll:
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6770
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Erstes Zeichen im String bei [0]

Beitrag von af0815 »

Mathias hat geschrieben: Mo 7. Apr 2025, 13:08 Was mir noch ein sympatisches Features wäre, wen ein statisches array nicht immer ein ".." bräuchte, wen es mit 0 beginnt.
[JOKE ON] Hast dich C schon so verseucht [JOKE OFF]
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: Erstes Zeichen im String bei [0]

Beitrag von Mathias »

Übrigens so neu wäre dies in Pascal nicht, so was gibt es beim ShortString schon.

Code: Alles auswählen

var
  s: string[16];
[JOKE ON] Hast dich C schon so verseucht [JOKE OFF]
Genau, es kommt mit gerade keine andere Sprache in den Sinn welche ".." braucht.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: Erstes Zeichen im String bei [0]

Beitrag von Warf »

Mathias hat geschrieben: Mo 7. Apr 2025, 13:45 Genau, es kommt mit gerade keine andere Sprache in den Sinn welche ".." braucht.
Das liegt aber daran das Arrays in Pascal fundamental immer Assoziative Arrays sind. Also eigentlich Mappings von einem Typen auf einen anderen.

In C hat ein Array eine Größe, in Pascal ist der Index als Typ angegeben der auf einen anderen Typen gemapped wird:

Code: Alles auswählen

arr: Array[0..9] of Integer;
// Ist das gleiche wie
type T10Elems=0..9;
var
  arr: Array[T10Elems] of Integer;
Deshalb kann man auch Enums oder Booleans als Typen für Array Indizes nehmen. Es ist nämlich auf Theoretischer Ebene kein Container mit N elementen, sondern es ist eine Abbildung von einem Typen auf einen anderen. Tatsächlich kann man das Pascal Mengentheoretisch sehr gut herunterbrechen lassen:
1. Ordinal typen, diese können als Enums oder Ranges definiert werden. Alle Ordinaltypen lassen sich Mengentheoretisch als Untermenge der Ganzen Zahlen auffassen (Byte ist am ende auch nix anderes als 0..255, und Bool nur ein Enum (True, False), etc.)
2. Assoziative Arrays, die sich als Abbildung (Ordinal [x Ordinal x ...) -> Typ auffassen lassen
3. Kompsit Typen (records, objects), die theoretisch im grunde sich als Kreuzprodukt von anderen Typen
4. Funktionstypen, die im grunde wie Arrays eine Abbildung darstellen, aber nicht auf Ordinaltypen reduziert sind.

Es gibt Natürlich noch mehr, Floats machen jede Analyse etwas kompliziert, Bitgrößenrestriktionen geben technische limitierung, es gibt noch Sets, die aber aufgrund ihrer Limitation auf 255 Elemente eher mäßig nützlich sind. Und natürlich Pointer und Seiteneffekte die jedwede Theoretische Analyse kaputt machen. Und variante Records formen ein Algebraisches Typsystem wie man es z.B. auch aus Funktionalen Sprachen kennt.

Es gibt andere Sprachen die das auch so machen. In JavaScript hat auch ein sehr simples typsystem. Es gibt Floats, Strings, Dictionaries und Lambdas. Genau wie in Pascal gibt es keine Arrays per se, sondern es sind auch nur Dictionaries.

In Haskell gibt es auch keine Arrays, das nutzt Algebraische Strukturen um Listen rekursiv abzubilden.

C artige Arrays sind tatsächlich mMn sehr langweilig weil sie halt technischer Natur sind nicht Mathematischer. Das Pascal Typsystem könnte in der Theorie deutlich mächtiger sein (in der Praxis ists aber auch an die Technische Kompatibilität gebunden)

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

Re: Erstes Zeichen im String bei [0]

Beitrag von Socke »

Warf hat geschrieben: Mo 7. Apr 2025, 21:50
Mathias hat geschrieben: Mo 7. Apr 2025, 13:45 Genau, es kommt mit gerade keine andere Sprache in den Sinn welche ".." braucht.
Das liegt aber daran das Arrays in Pascal fundamental immer Assoziative Arrays sind. Also eigentlich Mappings von einem Typen auf einen anderen.
Dem widerspreche ich. Pascal hat einen ordinalen Array-Index. Das hat wenig mit Assoziation sondern mehr mit Typumwandlung zu tun. Du kannst z.B. keine Strings, Pointer oder Arrays als Index verwenden, was bei echten assoziativen Arrays der Fall ist.

Enums, Boolean und Char sind alle ordinale Typen, d.h. mann kann sie in einer Reihenfolge abzählen:
  • Den Elementen eines Enums werden implizit oder explizit individuelle nummerische Werte zugewiesen.
  • Bei Boolean gibt es fixe Werte (False = 0, True = -1).
  • Char wird einfach in ein Byte konvertiert. Mit UnicodeChar sollte das ebenfalls funktionieren (Word).
Wenn du Assoziationen nutzen willst, musst auf Maps, Hash Listen etc. umschwenken. Diese verwalten die Daten dann als Arrays, verkettete Listen oder Bäume.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

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

Re: Erstes Zeichen im String bei [0]

Beitrag von Warf »

Socke hat geschrieben: Di 8. Apr 2025, 09:54 Dem widerspreche ich. Pascal hat einen ordinalen Array-Index. Das hat wenig mit Assoziation sondern mehr mit Typumwandlung zu tun. Du kannst z.B. keine Strings, Pointer oder Arrays als Index verwenden, was bei echten assoziativen Arrays der Fall ist.

...

Wenn du Assoziationen nutzen willst, musst auf Maps, Hash Listen etc. umschwenken. Diese verwalten die Daten dann als Arrays, verkettete Listen oder Bäume.
Das ist eine technische limitation, keine limitation auf Sprachebene. Wenn morgen ein FPC Update käme was transparent komplexe Datentypen bei arrays als hashmap abbilden würde, würde sich an der Sprachdefinition absolut nix ändern.

Arrays sind definiert als

Code: Alles auswählen

array[<TypeDecl List>] of <TypeDecl>
Das technisch das ganze nur umgesetzt ist für ordinal Typen ändert semantisch nix daran das es ein mapping von Typen auf Typen ist.

Pascal ist eine Hochsprache, das die sprachsemantik auf bestimmte technische Konzepte abbildet ist mehr eine Sache der convinience (und ABI stabilität) als ein festes Gesetz.
Das haben wir ja bereits schon beim case Statement gehabt, original weil's technisch eine jumping table ist, nur auf ordinal Typen definiert, mittlerweile geht's auch auf Strings, weil die Semantik der Hochsprache unabhängig von der unterliegende Implementation ist.
Bei Boolean gibt es fixe Werte (False = 0, True = -1).
Nicht ganz, bei booleans ist's 0 und 1 und bei longbool und Konsorten ist's 0 und -1 da bei letzteren logisches und bitweises Not identisch sind, während beim ersten erlaubt mit dem Ergebnis von vergleichen zu rechen und damit geht z.B. das folgende:

Code: Alles auswählen

sign := ord(x>=0)*2-1

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

Re: Erstes Zeichen im String bei [0]

Beitrag von Socke »

Warf hat geschrieben: Di 8. Apr 2025, 14:39 Arrays sind definiert als

Code: Alles auswählen

array[<TypeDecl List>] of <TypeDecl>
Das technisch das ganze nur umgesetzt ist für ordinal Typen ändert semantisch nix daran das es ein mapping von Typen auf Typen ist.
Tatsächlich haben die Free Pascal Entwickler, eine andere Definition dokumentiert: https://www.freepascal.org/docs-html/cu ... 500003.3.1
Es sind hier wirklich nur ordinale Typen als Arrayindex zugelassen. Auf einer semantischen Ebene kann man das natürlich anders betrachten und bei einem hypothetischen Update auch die Definition/Dokumentation ändern.

Da Pascal durchaus direkten Speicherzugriff erlaubt und das Speicherlayout auch für Arrays definiert (siehe Programmer's Guide, 8.2.9 und 8.2.10), habe ich wenig Hoffnung, dass die bisherige Praxis in naher Zukunft geändert wird.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

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

Re: Erstes Zeichen im String bei [0]

Beitrag von Warf »

Es muss ja nicht geändert werden, kann aber erweitert werden. Bei ordinal Typen wie gehabt, bei komplexen Typen anderes verhalten. Das gesagt das wird nicht passieren weil es bereits verschiedene Implementationen für hashmaps gibt und es nur extra Aufwand im Compiler wäre (hatte schonmal gefragt für Strings im speziellen, da Strings sehr fundamentale Typen sind)

Antworten