Ord- und Length-Funktion im FPC-Quellcode gesucht

Für allgemeine Fragen zur Programmierung, welche nicht! direkt mit Lazarus zu tun haben.
Antworten
Nixsager
Beiträge: 168
Registriert: Sa 8. Okt 2016, 08:38
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Wohnort: Polska

Ord- und Length-Funktion im FPC-Quellcode gesucht

Beitrag von Nixsager »

Hi

Anstatt die Length-Funktion zu nutzen, habe ich für ein ShortString die Ord-Funktion genutzt.

Ich wollte genauer wissen, wie diese Funktionen funktionieren, nur leider finde ich sie nicht wirklich.

Ich habe mal beides genutzt, aber nach der Kompilierung ist das Kompilat bzw. das Programm identisch.

Ord-Variante:

Code: Alles auswählen

	If TestString[Ord(TestString[0]) - 1] = '8' then
		WriteLn('Vorhanden');
Length-Variante:

Code: Alles auswählen

	If TestString[Length(TestString) - 1] = '8' then
		WriteLn('Vorhanden');
Kann mir jemand sagen wo ich die Funktionen suchen muss?

Gruß vom Nixsager
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

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

Re: Ord- und Length-Funktion im FPC-Quellcode gesucht

Beitrag von Jorg3000 »

Hi!
Meines Wissens ist Ord() keine echte Funktion, sondern nur ein Compiler-interner Typecast, d.h. ein Char oder ein Aufzählungstyp wird dann wie ein Byte behandelt.

Bei Shortstring funktioniert es mit Ord(Shortstring[0]) nur deshalb, weil im ersten Byte des Shortstrings die tatsächlich belegte Zeichenanzahl im Shortstring gespeichert ist.
Eigentlich liefert Shortstring[0] ein Char, aber durch den Ord()-Typecast wird es zu einem Byte, und ist somit quasi wie Length(AnsiString) verwendbar.

Wenn das Kompilat gleich ist, bedeutet das wohl, dass der Kompiler bei Length(Shortstring) exakt das Gleiche macht wie Ord(Shortstring[0]).
Grüße, Jörg

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

Re: Ord- und Length-Funktion im FPC-Quellcode gesucht

Beitrag von Jorg3000 »

PS:
Und für Length() findet man ebenfalls keinen Quellcode, weil es sich vermutlich ebenfalls nicht um eine echte Funktion handelt, sondern um "Compiler Magic".

Ohne in den erzeugten Assembler-Code geschaut zu haben, nehme ich an, dass der Compiler für Length(AnsiString/UnicodeString) automatisch Code erzeugt, der zuerst prüft, ob der String leer ist (intern ein Pointer mit Wert NIL) und dann ggf. Länge 0 zurückliefert, oder wenn der String-Pointer <>nil ist, die Längenangabe aus dem String-Speicher liest, entweder als 32- oder 64-Bit-Wert (SizeInt).

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

Re: Ord- und Length-Funktion im FPC-Quellcode gesucht

Beitrag von Warf »

Weder Ord noch Length sind tatsächlich funktionen, ich glaube der Term dafür ist Intrinsics. Die sehen zwar aus wie Funktionen, werden aber vom Compiler anders behandelt und können damit sachen die Funktionen nicht können.

Length gibt die Länge von arrays und strings zurück. Für statische Arrays wird das zur Kompilezeit einfach durch die Größenkonstante ersetzt, bei Dynamischen Arrays wird gecheckt wenn der Array nil ist dann 0, ansonsten wird der Pointer Dereferenziert und das Längenfeld des Dynamischen Arrays gelesen.
Bei Strings ist es so ähnlich, bei Statische (short)strings wird einfach das erste Byte gelesen, bei dynamischen (Ansi)Strings sehr ähnlich nil -> 0 sonst dereferenziert und Längenfeld des dynamischen Strings gelesen.

Ord ist einfach nur eine Typconversion, die Ordinale typen (d.h. typen die intern als eine Ganzzahl dargestellt werden) in ihre Ordinale Repräsentation überführen. Ordinale typen sind z.B. Enums oder Chars. Ord('A') z.B. ist 65 denn der Character 'A' ist in ANSI (und UTF-8) der Codepunkt 65. Das gegenstück von Ord ist Chr, wobei Chr(65) dann der Char 'A' wäre.
Das ist übrigens eine reine Typrepresentationsänderung zur Compilezeit und führt keinen Laufzeitcode aus, denn Chars werden so oder so zur Laufzeit als Zahlen representiert (am ende sind alles bytes), Ord erlaubt dir nur im Programmcode Chars als Zahlen zu behandeln.

Beispiel, um die Chars '0' bis '9' in die Zahlen 0-9 umzuwandeln, kannst du einfach Ord Benutzen:

Code: Alles auswählen

function CharToNum(c: Char): Integer;
begin
  if not (c in ['0'..'9']) then
    Exit(-1); 
  Result := Ord(c) - Ord('0'); // Hiermit wird '0' auf 0 gemapped und alle weiteren zahlen sind einfach linear von hier
end;
Was dein Code Beispiel mit Ord macht ist damit ganz einfach, im ersten Byte eines ShortStrings steht die Länge, allerdings mit der Notation Str[n] greifst du auf die Einzelnen Chars zu, bekommst also den wert als Char typ. Um jetzt damit zu rechnen musst du diesen Char in eine Zahl umwandeln, und das machst du mit Ord.

Pascal ist voll mit solchen Intrinsics, z.B. Exit was oben benutzt ist ist offensichtlich auch keine Funktion, denn eine Funktion die man aufruft kann (bzw sollte es nicht können) die Aufrufende Funktion ändern (in diesem Fall beenden).

Andere Intrisics sind z.B. Write(ln), deshalb geht sowas:

Code: Alles auswählen

WriteLn('Hallo', 42, 3.14);
Man kann beliebige parameter beliebigen types angeben, es ist unmöglich eine solche funktion selbst in purem Pascal zu schreiben

Nixsager
Beiträge: 168
Registriert: Sa 8. Okt 2016, 08:38
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Wohnort: Polska

Re: Ord- und Length-Funktion im FPC-Quellcode gesucht

Beitrag von Nixsager »

Danke für die Antworten.

Das bei ShortString an Position 1 (oder 0) die Länge des Strings steht, war mir klar, deswegen hatte ich Ord benutzt.
Aber das es abgesehen vom Quellcode keinen Unterschied macht, ob man für einen ShortString Ord oder Length nutzt, hätte ich nicht gedacht.

Ich probiere bei manchen Funktionen aus, welches im Kompilat kleiner ist.

Das mit den intrinsische Funktionen (für mich sind das interne/Grund- Funktionen/Befehle) macht natürlich sinn, sonnst könnte der Kompilierer ja den Code nicht kompilieren, und die zusätzlichen Funktionen/Prozeduren nutzbar machen.
Anders gesagt, wenn einer die Wörter nicht kennt, kann den Text nicht lesen.

Diese internen Befehle werden ja in den Dateien 'sysstrh.inc', 'system.fpd' und sicherlich noch ein paar anderen angegeben.
Aber irgendwo muss doch der Code vorhanden sein, wie der Kompilierer mit diesem Code umzugehen hat.
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

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

Re: Ord- und Length-Funktion im FPC-Quellcode gesucht

Beitrag von Warf »

Viele Intrisics rufen Tatsächlich Intern funktionen auf die sind relativ einfach zu finden, z.B. SetLength ruft auf einem shortstring einfach diese funktion auf:

Code: Alles auswählen

procedure fpc_Shortstr_SetLength(var s:shortstring;len:SizeInt);[Public,Alias : 'FPC_SHORTSTR_SETLENGTH']; compilerproc;
begin
  if Len>255 then
   Len:=255;
  s[0]:=chr(len);
end;
Beispiel:

Code: Alles auswählen

procedure Foo;
var
  s: ShortString;
begin
  SetLength(s, 10);
end;
Wird Kompiliert zu:

Code: Alles auswählen

foo():
        pushq   %rbp
        movq    %rsp,%rbp
        leaq    -256(%rsp),%rsp
        leaq    -256(%rbp),%rax
        movq    $10,%rdx
        movq    $255,%rsi
        movq    %rax,%rdi
        call    fpc_shortstr_setlength
        movq    %rbp,%rsp
        popq    %rbp
        ret
Mit dem call zu fpc_shortstr_setlength klar sichtbar. Diese funktionen sind im source recht einfach zu finden. Das ding bei den ganz simplen Intrinsics wie Length oder Ord ist das die ja keine echte Funktionalität haben. Sie sind reiner Syntaktischer Zucker.

Beispiel:

Code: Alles auswählen

var
  c: Char;
  b: Byte;
begin
  b := Ord(c);
Kompiliert zu:

Code: Alles auswählen

        movb    -4(%rbp),%al
        movb    %al,-8(%rbp)
Der Folgende Code:

Code: Alles auswählen

var
  b1, b2: Byte;
begin
  b1 := b2;
Kompiliert auch zu:

Code: Alles auswählen

        movb    -8(%rbp),%al
        movb    %al,-4(%rbp)
Ord hat also absolut keine Funktionalität, es ist purer Syntaktischer Zucker der lediglich den Typchecker befriedigt.
Und weil Ord keine Funktionalität hat, findest du natürlich auch keine Code der die Funktionalität von Ord implementiert.

Genauso mit Length:

Code: Alles auswählen

procedure Foo;
var
  s: ShortString;
  b: Byte;
begin
  b := Length(s);
end;
Kompiliert zu:

Code: Alles auswählen

        movb    -256(%rbp),%al
        movb    %al,-260(%rbp)
Verglichen mit:

Code: Alles auswählen

var
  arr: array[0..255] of Byte;
  b: Byte;
begin
  b := arr[0];
Kompiliert auch zu:

Code: Alles auswählen

        movb    -256(%rbp),%al
        movb    %al,-260(%rbp)
Auch hier hat Length keine besondere Funktion, es ist schlicht und ergreifend syntaktischer Zucker um den Array zugriff ein bisschen schöner zu gestalten.

Von daher gibt es keine direkte implementierung von denen, sie sind einfach fester bestanteil des Typsystems

wp_xyz
Beiträge: 4895
Registriert: Fr 8. Apr 2011, 09:01

Re: Ord- und Length-Funktion im FPC-Quellcode gesucht

Beitrag von wp_xyz »

Nixsager hat geschrieben:
Do 27. Jul 2023, 16:49
Das bei ShortString an Position 1 (oder 0) die Länge des Strings steht, war mir klar, deswegen hatte ich Ord benutzt.
Den Zugriff auf das nullte Byte solltest du dir gar nicht angewöhnen. Denn wenn du irgendwann einmal mit "echten" (dynamischen) Strings zu tun hast, hast du ein Problem mehr...

Ich habe zahlreiche Units aus Turbo-Pascal-Zeiten, die eigentlich zu schade sind zum Wegwerfen, deren Reaktivierung und Aktualisierung in Lazarus aber daran scheitert, dass ich damals diese Mikro-Optimierung gemacht habe, und ich mir heute nicht die Zeit nehmen will, alle Code-Stellen zu suchen.

siro
Beiträge: 732
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Ord- und Length-Funktion im FPC-Quellcode gesucht

Beitrag von siro »

ich habe früher in Turbo Pascal auch gerne auf das Nullte Byte (also die Länge zugegriffen)
aus heutiger Sicht eine Sünde :P aber früher gabs ja nur die ShortString....

Code: Alles auswählen

  s:='1234567890';
  dec(s[0],3);       // die letzten 3 Zeichen löschen
  writeln(s);        // ergibt 1234567           
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

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

Re: Ord- und Length-Funktion im FPC-Quellcode gesucht

Beitrag von Mathias »

Gibt es da einen Unterschied, oder ist die nur ein Relikt aus der TP-Zeit ?

Code: Alles auswählen

  WriteLn(chr(65));
  WriteLn(Char(65));

  WriteLn(Ord('A'));
  WriteLn(Byte('A'));    
ich habe früher in Turbo Pascal auch gerne auf das Nullte Byte (also die Länge zugegriffen)
aus heutiger Sicht eine Sünde :P aber früher gabs ja nur die ShortString....
Das stimmt, man sollte die vermeiden, ausser man weis was man tut. ZB. bei der AVR-Programmieren oder sonstige Spezialfälle,
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: Ord- und Length-Funktion im FPC-Quellcode gesucht

Beitrag von Warf »

Mathias hat geschrieben:
Fr 28. Jul 2023, 08:18
Gibt es da einen Unterschied, oder ist die nur ein Relikt aus der TP-Zeit ?
Relikt aus TP-Zeit. Aus der Doc: https://www.freepascal.org/docs-html/cu ... m/ord.html
Originally, Pascal did not have typecasts and ord was a necessary function in order to do certain operations on non-integer ordinal types. With the arrival of typecasting a generic approach became possible, making ord mostly obsolete. However ord is not considered deprecated and remains in wide use today.
Aber ich benutze es tatsächlich trozdem gerne, denn Typcasts können runtime code ausführen:

Code: Alles auswählen

operator Explicit(const s: String): Integer;
begin
  Result := StrToInt(s);
end;

begin
  WriteLn(Integer('42'));
end.
Zwar lassen sich Casts von Ordinaltypen nicht überladen:

Code: Alles auswählen

operator Explicit(c: Char): Byte; // Nicht überladbarer operator
Da das allerdings nicht dokumentiertes verhalten ist, könnte es sich jederzeit Ändern. Ord hingegen wird sich vermutlich nie mehr ändern.

PascalDragon
Beiträge: 834
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Ord- und Length-Funktion im FPC-Quellcode gesucht

Beitrag von PascalDragon »

Nixsager hat geschrieben:
Do 27. Jul 2023, 16:49
Diese internen Befehle werden ja in den Dateien 'sysstrh.inc', 'system.fpd' und sicherlich noch ein paar anderen angegeben.
Aber irgendwo muss doch der Code vorhanden sein, wie der Kompilierer mit diesem Code umzugehen hat.
Der Compiler weiß, dass Ord und Co intrinsische Funktionen sind und der entsprechende Code wird dann direkt vom Compiler generiert. Der Code von z.B. Ord ist also so gesehen Teil des Compilers.

Im Fall von Ord ist dies in compiler/ninl.pas in den verschiedenen Methoden von tinlinenode (v.a. pass_typecheck und simplify) jeweils unter dem Zweig für in_ord_x.
FPC Compiler Entwickler

Antworten