Konvertierung von C/C++ nach Pascal/Lazarus?

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1430
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von fliegermichl »

KreuzBlick hat geschrieben:1. Wie erzeuge ich in Visual Studio eine dll?
2. Wie rufe ich eine solche dll in Lazarus auf.


Aufrufen einer Funktion, die in einer in C erstellten DLL definiert ist:

Code: Alles auswählen

 
const dllname = 'einecdll.dll';
 
function cfunc(param1 : PChar; param2 : longint) : longint; cdecl; external einecdll;
 


Das wäre die statische Variante. Die kann dann einfach mit cfunc(a, i) aufgerufen werden.
Nachteil ist, daß das Programm einfach mit einer Fehlermeldung abgebrochen wird, falls einecdll.dll nicht vorhanden ist. Deshalb habe ich mir angewöhnt das dynamisch zu machen und das geht so:

Code: Alles auswählen

 
uses
 dynlibs;
type
 TCFunc = function(a : PChar; i : longint) : longint; cdecl;
const
 dllname = 'einecdll.'; // Hier ohne Dateiendung. Die wird von dynlibs abhängig vom System geliefert.
var
 CFunc : TCFunc = nil;
 DLLHandle : THandle;
initialization
 DLLHandle := LoadLibrary(einecdll + SharedSuffix);
 if DLLHandle <> 0 then
 begin
  CFunc := GetProcAddress(DLLHandle, 'cfunc');
 end;
end.
 


Jetzt kann man prüfen, ob CFunc = nil ist und entsprechend reagieren oder sie aufrufen mit CFunc(a, i);

Wie man in Visual Studio eine DLL erstellt, kann ich nicht sagen. Man kann aber auch eine mit C kompilierte Datei direkt in Lazarus einbinden.

Code: Alles auswählen

 
 
{$LINK cfunc.o} // Diese sollte die function cfunc enthalten
 
 function cfunc (a : PChar; i : longint) : longint; cdecl; external;
 

BeniBela
Beiträge: 308
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von BeniBela »

Niesi hat geschrieben:Also, außer, dass dies dann vielleicht nicht so toll "Schick schick schickimicki" oder "Hipp Hipp Hippsterle" wäre?

Und noch interessanter ist für mich Deine Begründung dafür, welche SACHLICHEN Gründe denn GEGEN die Verwendung von Lazarus und Free-Pascal sprechen?

Das man sich in Pascal selbst darum kümmern muss, ob Variablen gültige Werte enthalten

Da kriegt man dann Probleme mit uninitialisierten Variablen, nicht freigegebenem Speicher oder unerwarteten nil Referenzen. Sowas sollte es in modernen Sprachen nicht mehr geben

pluto
Lazarusforum e. V.
Beiträge: 7178
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von pluto »

Da kriegt man dann Probleme mit uninitialisierten Variablen, nicht freigegebenem Speicher oder unerwarteten nil Referenzen. Sowas sollte es in modernen Sprachen nicht mehr geben

Der Boolean Datantypt: Wenn man ihn nicht mit einem Wert belegt, ist er weder True noch False.
MFG
Michael Springwald

KreuzBlick
Beiträge: 36
Registriert: Fr 3. Mai 2019, 17:45
OS, Lazarus, FPC: Win8.1 (L 2.2.4 FPC 3.2.2)
CPU-Target: 64Bit
Wohnort: Saarland

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von KreuzBlick »

Vielen Dank, fliegermichl.
Wie man in C/C++ eine dll erstellt, habe ich herausgefunden, und dank deiner Hilfe konnte ich die statische Variante des Aufrufs auch schon ausprobieren.

Hinter external muss natürlich der Konstantenname stehen und nicht der Dateiname der dll. Aber das war eigentlich gleich klar.

Die übrigen Dinge muss ich bei Gelegenheit noch probieren.

Ansonsten gegen in dieser Diskussion zwei Themen durcheinander. Ich weiß nicht, ob es einen Moderator gibt, der alle Beiträge, die sich mit dem Vergleich von Programmiersprachen beschäftigen, an eine andere Stelle verschieben könnte, da sie hier off topic sind.
Viele Grüße
Gerold

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

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von Timm Thaler »

BeniBela hat geschrieben:Da kriegt man dann Probleme mit uninitialisierten Variablen...


Wie bitte schaffst Du es in Pascal, uninitialisierte Variablen zu verwenden?

pluto hat geschrieben:Der Boolean Datantypt: Wenn man ihn nicht mit einem Wert belegt, ist er weder True noch False.


Ich weiß ja nicht, was ihr für ein Pascal habt, aber bei mir ist ein Integer ohne Zuweisung immer 0 und ein Boolean immer False. Das ist selbst auf dem AVR so, da wird am Anfang erstmal der Ram genullt.

pluto
Lazarusforum e. V.
Beiträge: 7178
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von pluto »

Wie bitte schaffst Du es in Pascal, uninitialisierte Variablen zu verwenden?

Das geht sehr gut, wenn man auf die Warnungen vom FPC nicht reagiert. Ich habe gelernt, darauf inzwischen zu achten.

Ich weiß ja nicht, was ihr für ein Pascal habt, aber bei mir ist ein Integer ohne Zuweisung immer 0 und ein Boolean immer False. Das ist selbst auf dem AVR so, da wird am Anfang erstmal der Ram genullt.

Ein Boolean ist False, ja, aber du kannst diesen Variable nicht nutzen, jedenfalls ist mir das mal aufgefallen, seit dem belege ich mein Variablen immer mit einem Passenden Wert oder auch Variablen Klassen, die ich mit NIL belege.
Damit ich sie abfragen kann. Versuch mal eine Variable Klasse abzufragen, die du nicht Installisiert hast oder mit einem Wert belegt hast.
Jedenfalls habe ich diese Erfahrung gemacht vor einiger ganzen Weile.
MFG
Michael Springwald

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

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von Warf »

Timm Thaler hat geschrieben:Ich weiß ja nicht, was ihr für ein Pascal habt, aber bei mir ist ein Integer ohne Zuweisung immer 0 und ein Boolean immer False. Das ist selbst auf dem AVR so, da wird am Anfang erstmal der Ram genullt.


Na dann führ doch einfach mal dieses Program aus:

Code: Alles auswählen

program Test;
 
procedure foo();
var a: Integer;
begin
  WriteLn(a);
  a := 42;
end;
 
begin
  foo();
  foo();
end.


Der grund ist, Pascal garantiert keine wert für uninitialisierte Variablen. D.h. der wert der in der Variable steht ist der der an dieser memory location steht.
Wenn du das programm oben austestest sollte das folgende geschehen: Beim ersten aufruf von foo wird speicher auf dem stack für a alloziiert. Der stack ist sauber also steht da ne 0 drin. Nach dem die funktion foo verlassen wird wird der stack pointer wieder reduziert. Beim nächsten aufruf wird wieder neuer speicher alloziiert, der, da es sich um die selbe funktion mit selber signatur handelt, genau so belegt wird wie beim ersten aufruf. Das a des zweiten aufrufs liegt also der selben stelle wie das erste a. im ersten durchlauf wurde an diese stelle 42 geschrieben, daher ist die ausgabe dieses programms erst 0 und danach 42.
Getestet unter 64 bit linux 4.19 mit fpc 3.0.4. Da es sich hierbei um undefiniertes verhalten handelt, kann das bei einem unterschiedlichen system natürlich auch komplett unterschiedlichen code erzeugen, ist also eventuell nicht immer reproduzierbar.

pluto hat geschrieben:Ein Boolean ist False, ja, aber du kannst diesen Variable nicht nutzen, jedenfalls ist mir das mal aufgefallen, seit dem belege ich mein Variablen immer mit einem Passenden Wert oder auch Variablen Klassen, die ich mit NIL belege.
Damit ich sie abfragen kann. Versuch mal eine Variable Klasse abzufragen, die du nicht Installisiert hast oder mit einem Wert belegt hast.
Jedenfalls habe ich diese Erfahrung gemacht vor einiger ganzen Weile.

Beim boolean ist es ein besonderer fall, ein Boolean ist true solang im unterliegenden speicher eine zahl steht die nicht 0 ist. True als konstante (also wenn man schreib b:=true) ist der Numerische wert -1 oder 1 (glaube es war mal -1 oder ist -1 auf windows, auf meinem linux bekomm ich aber grade 1 raus). Beispiel

Code: Alles auswählen

program Test;
 
var b: boolean;
var p: ^Byte;
begin
  p := PByte(@b);
  p^ := 42;
  if b = true then writeLn('true');
  b := true;
  writeln(p^);
end.

Ergebnis: True und 1.

Das problem mit Klassen das du ansprichst ist da etwas anders. Bei dem beispiel oben mit der funktion foo, wird die variable a damit initialisiert was zufällig an der speicherstelle vorher stand. Das ist soweit ja auch kein problem, bei klassen wirds aber lustig, denn klassen sind intern auch nur zeiger. Und wenn in einem Zeiger ein undefinierter wert drin steht ist das natürlich ein ganz anderes problem als wenn das in einem normalen objekt steht. Beim dereferenzieren (also zugreifen auf klassenelemente) wird also geschaut was steht an der adresse auf die der Zeiger zeigt. Da die undefiniert ist kann das alles sein. Und das ist besonders schlimm wenn es auf einen echten Speicherbereich zeigt, da man damit dann die daten aus einer ganz anderen Klasse bearbeiten kann, ohne es zu merken.
Beispiel:

Code: Alles auswählen

program test;
{$MODE ObjFPC}{$H+}
 
function Bar(): PInteger;
begin
  new(Result);
  Result^ := 24;
end;
 
procedure Foo;
var p: ^Integer;
begin
  p^ := 42;
end;
var p: ^Integer;
begin
  p:= bar;
  foo;
  WriteLn(p^);
end.


Zu guter letzt, wo wir grade beim Thema sind, man sollte auch immer brav freeAndNil statt free benutzen, sonst passiert sowas:

Code: Alles auswählen

program Test;
{$MODE OBJFPC}{$H+}
 
type
  TTest = class
  public
    A: Integer;
    B: Integer;
  end;
 
var
  t1, t2: TTest;
begin
  t1 := TTest.Create;
  t1.free;
  t2 := TTEst.Create;
  t1.A := 42;
  t1.B := 15;
  WriteLn(t2.A, ' ', t2.B);
end.


Zu dem Thema ist Pascal modern, von mir ein ganz klares nein. Pascal ist bewusst nicht modern. Was ich damit meine ist nicht unbedingt pascal ist nicht aktuell, aber es basiert völlig auf alten konzepten.
Nehmen wir statt rust o.ä. einfach mal C++ als beispiel. C++ und Object Pascal sind ähnlich alt, dennoch hat C++ mit C++11 eine gewaltige Modernisierung erfahren. Um mal zwei modernisierungen zu nennen wäre das 1. Einführen von Ownership konzepten, sodass die Speicherbereinigung impliziet durch destruktoren übernommen wird (std::unique_ptr, std::shared_ptr, etc.)
2. Einführen von Lambdas und Funktionen als Objekte (std::function, funktionsoperator, etc.)

Ob diese änderungen besser oder schlechter sind, darüber lässt sich streiten, aber, C++ Code von vor 2011 ist damit Konzeptionell komplett anders als Code nach 2011. Bei pascal wiederum ist die neuste größere änderung die implementation von Generics und Namespaces oder Typhelpern, änderungen die von der Struktur keinen großen Unterschied machen. Ein Delphi 7 Programm sieht immernoch fundamental gleich aus, benutzt die selben Paradigmen und den selben Code stil, wie ein aktuelles Lazarus projekt, und bis auf kleinere anpassungen kann man viele aktuelle Lazarus projekte (rein syntaktisch, nicht von den Komponenten/libs) auch wieder Delphi 7 fähig machen. Es gab keinen fundamentalen wechsel in Pascal, so wie es ihn in C++ gab.
C ist zum beispiel eine Sprache die zwar geupdated wird, aber, sowie pascal, eher wenig modernisiert wird. Grade in den letzen jahren kam man viel auf die Idee, jetzt wo leistung und speicher recht billig ist, bei Programmiersprachen mehr syntaktische mittel zu geben. z.B. Sprachen wie C# haben einen definierten wert für jeden typen wenn eine Variable nicht initialisiert wird. Im endeffekt heißt das, eine schreiboperation pro Variable mehr. In den 70ern, als Pascal entwickelt wurde, war das einfach verschwendete laufzeit, heute macht die halbe nanosekunde nichts aus.
Sprachen wie Rust, Go, C# oder andere versuchen aktiv aus dem bisher festgefahrenen Paradigmen auszusteigen, und neue Wege zu implementieren um Programmcode leserlicher, robuster und weniger Fehleranfällig zu machen, während alte Sprachen sich oft eher daran orientiert haben wie es letzendlich auf der Hardware laufen muss.

Und das ist in vieler hinsicht ziemlich gut. So sind in rust z.B. speicherlecks mehr oder weniger unmöglich zu erzeugen, und bei den vielen Nächten die ich schon wegen eines Speicherzugriffsfehler durchgemacht hab kann ich das nur gutheißen. Oder, um bei rust zu bleiben, bietet Rust durch seine Syntax dem Kompiler die möglichkeit diverse sachen formal zu verifizieren. Der kompiler kann also die teilkorrektheit deines Codes deutlich besser überprüfen als bei einer sprache die nicht so designt wurde, z.B. pascal. Daher bekommst du in rust viel bessere und mehr fehlermeldungen. Zu der zeit als Pascal entwickelt wurde wäre formale verifikation rein von der Performance zur Kompilezeit nicht möglich gewesen.

Aber ganz ehrlich, ich mag pascal grade weil es nicht so modern ist. Man ist komplett auf der Maschiene. Es gibt keine komplizierten Konstrukte, bei denen mir als entwickler völlig unklar ist wie der generierte Assembly code dann aussehen wird. Die ganzen spielereien von oben, das Pointer gemenge, etc. ist nur möglich weil das was ich in Pascal mache, direkt den generierten Maschinencode wiederspiegelt. Und als jemand der sich für den ganzen Low-Level kram interresiert ist das natürlich viel schöner als in einer Sprache die mir all diese sachen verbietet, bzw. bei der ich nicht verstehen kann was am ende passiert (und da die andere option dafür C wäre, ist Pascal mir doch um einiges lieber).



Um aber mal wieder zum Thema zurück zu kommen:
Wie man in Visual Studio eine DLL erstellt, kann ich nicht sagen. Man kann aber auch eine mit C kompilierte Datei direkt in Lazarus einbinden.

Code: Alles auswählen

 
 
{$LINK cfunc.o} // Diese sollte die function cfunc enthalten
 
 function cfunc (a : PChar; i : longint) : longint; cdecl; external;
 

Ist wohl das einfachste.

Das konzept ist so. Mit C (und Unix und später Linux) wurde das ELF binary format (Executable Linkage format) eingeführt. Die idee ist grundsätzlich so. Eine kompilationsunit enthält einen bestimmten Programmcode. Diese Unit exportiert dabei funktionen, und importiert funktionen. Z.B. betrachten wir diesen C file:

Code: Alles auswählen

void WriteLn(const char *);
 
int main() {
  WriteLn("Hallo Welt!");
  return 0;
}

Dieses program exportiert die Funktion main, und importiert die Funktion WriteLn.
Wenn ich das ganze kompiliere zu einem Object File (gcc -c ./test.c), so erhalte ich diese unfertige kompilationsunit. Damit ich daraus jetzt ein Programm machen kann, muss ich die importierte Funktion WriteLn bereit stellen.
Nehme ich jetzt eine zweite C datei:

Code: Alles auswählen

void WriteLn(char const *str) {
  printf("%s\n", str);
}

So exportiert diese die funktion WriteLn (und importiert printf, die lass ich jetzt aber einfach mal untern tisch fallen). Wenn ich jetzt also die beiden Object files habe (test.o und writeln.o), so kann ich die zusammen linken und somit die Funktion WriteLn in der test.c benutzen:

Code: Alles auswählen

$> gcc -c test.c
$> gcc -c writeln.c
$> gcc -o test test.o writeln.o

Das dabei resultierende Programm test verwendet die main funktion die in der test.c exportiert wird, und ruft darin die WriteLn auf die von writeln.c exportiert wird.

Der FPC unterstützt auch die nutzung von ELF object files (auch wenn pascal als sprache im gegensatz zu C nicht auf ELF angewiesen ist). Somit kannst du praktisch ein projekt zur hälfte in C schreiben, die andere hälfte in Pascal, und am ende einfach alles zusammen linken (Ist einfacher gesagt als gemacht).
Das gesagt, willst du wahscheinlich doch lieber auf statische Bibliotheken oder Dynamische gehen, da das rumgehampel mit Object files ein bisschen dumm ist (so hast du einen Object File pro C file, bei einer Static Library, was eine sammlung von Object files ist, kannst du mehrere C Files gleichzeitig exportieren).
Ganz nett dazu istdieses tutorial: Link
Wenn du mit C und Pascal arbeitest solltest du dir aber mindestens mal was zu Aufrufkonventionen durchlesen, und eventuell willst du dann auch die cmem unit verwenden (ansonsten kannst du speicher der in C erzeugt wird in Pascal nicht freigeben und anders rum)

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 331
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon (Windows wenn notwendig), Lazarus 3.0 FPC 3.3.1

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von Niesi »

Timm Thaler hat geschrieben:
BeniBela hat geschrieben:Da kriegt man dann Probleme mit uninitialisierten Variablen...


Wie bitte schaffst Du es in Pascal, uninitialisierte Variablen zu verwenden?

pluto hat geschrieben:Der Boolean Datantypt: Wenn man ihn nicht mit einem Wert belegt, ist er weder True noch False.


Ich weiß ja nicht, was ihr für ein Pascal habt, aber bei mir ist ein Integer ohne Zuweisung immer 0 und ein Boolean immer False. Das ist selbst auf dem AVR so, da wird am Anfang erstmal der Ram genullt.



Dieses Thema ist sehr interessant - aber ich schlage vor, wir machen dazu eine eigenes Thema auf, denn sonst stören wir hier das eigentliche Thema, nämlich die Portierung von C nach Pascal.

Die Diskussion, ob Pascal zeitgemäß ist oder nicht, kann sehr interessant sein und auch beim Finden der "richtigen" Programmiersprache unterstützen. Ich hoffe, das ist auch in Eurem Sinne ...

Beste Grüße
Harald
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

pluto
Lazarusforum e. V.
Beiträge: 7178
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von pluto »

Der stack ist sauber also steht da ne 0 drin.

So, kann man natürlich die Falsche anmahne treffen: Pascal belegt alle Variablen mit einem Default wert auch wenn das nicht der Fall ist.

Zu guter letzt, wo wir grade beim Thema sind, man sollte auch immer brav freeAndNil statt free benutzen, sonst passiert sowas:

Wie, T1 kann nach dem Freigeben, immer noch "benutzt" werden?

Um mal zwei modernisierungen zu nennen wäre das 1. Einführen von Ownership konzepten, sodass die Speicherbereinigung impliziet durch destruktoren übernommen wird (std::unique_ptr, std::shared_ptr, etc.)
2. Einführen von Lambdas und Funktionen als Objekte (std::function, funktionsoperator, etc.)

Lambdas habe ich schon öfter gehört jetzt. ich muss mal schauen, was damit genau gemeint ist.

Ob diese änderungen besser oder schlechter sind, darüber lässt sich streiten, aber, C++ Code von vor 2011 ist damit Konzeptionell komplett anders als Code nac

Ob, es gut ist, in eine "Alte" Sprache solche gewaltigen Eingriffe zu machen, ist natürlich Fraglich.

Ein Delphi 7 Programm sieht immernoch fundamental gleich aus, benutzt die selben Paradigmen und den selben Code stil

Ich habe vor einigen Tagen ein Object Pascal Code gesehen, dass nutzte "Aktuelle" Möglichkeiten von Object Pascal z.b. Generics. Die meisten Klassen, sind eher nach dem alten Style und Konzepten aufgebaut.... Immer nach dem gleichem muster. Mir ist aber bis dahin noch keine Komponente unter gekommen, die so gut strukturiert ist und eben komplett auf "Generics" setzt.
Ich wollte mich damit ja eigentlich nicht befassen, aber ich werde es mir wohl anschauen müssen. Alleine schon aus dem Grund, weil Rust, darauf aufbaut.

Im endeffekt heißt das, eine schreiboperation pro Variable mehr. In den 70ern, als Pascal entwickelt wurde, war das einfach verschwendete laufzeit, heute macht die halbe nanosekunde nichts aus.

Das sind eben gewisse Unterschiede. Ob man es braucht oder nicht. Man spart sich Schreibarbeit, dass Programm läuft Stabiler und ist Sicherer.

Sprachen wie Rust, Go, C# oder andere versuchen aktiv aus dem bisher festgefahrenen Paradigmen auszusteigen, und neue Wege zu implementieren um Programmcode leserlicher, robuster und weniger Fehleranfällig zu machen, während alte Sprachen sich oft eher daran orientiert haben wie es letzendlich auf der Hardware laufen muss.

Wobei Rust, natürlich auch auf alte "Paradigmen" basiert, jedoch mit neuen Varianten.

Der kompiler kann also die teilkorrektheit deines Codes deutlich besser überprüfen als bei einer sprache die nicht so designt wurde

Außerdem macht der Kompiler Vorschläge, wie der Fehler zu beheben ist bzw. Zeigt, Beispiele, wie der Fehler auftreten kann....

Aber ganz ehrlich, ich mag pascal grade weil es nicht so modern ist. Man ist komplett auf der Maschiene.

Genau. Ich finde Pascal im gegensatzt zu C oder auch zu Rust, deutlich einfacher zu Lernen, weil es eben auch mehr in Deutsch gibt und es ändert sich nicht so Rasant. Das kann ein Nachteil sein, aber ich denke, es ist mehr ein Vorteil.

Die Diskussion, ob Pascal zeitgemäß ist oder nicht, kann sehr interessant sein und auch beim Finden der "richtigen" Programmiersprache unterstützen. Ich hoffe, das ist auch in Eurem Sinne ...

Es geht nicht darum, die RICHTIGE Programmiersprache zu finden, sondern die Programmiersprache zu Finden, die für dein Projekt am ehesten geeignet ist.
Auch wenn ich Pascal liebe, verwende ich lieber C(Arduino C) für AVR. Wegen STM32, schaue ich mir Rust(Die Einarbeitung wird aber noch eine ganze weile dauern) an.
Programmiersprachen sind auch "nur" Werkzeuge. Wenn man es so sieht. Wer mit Programmieren Geld verdienen möchte, sollte sich eher mit PHP oder Java befassen als mit Pascal(ist leider so in der Industrie, soweit ich weiß, es mag ausnahmen geben).

Ich denke, als Programmiere sollte man flexibel sein(auch wenn das schwer fällt).
MFG
Michael Springwald

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

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von Warf »

pluto hat geschrieben:So, kann man natürlich die Falsche anmahne treffen: Pascal belegt alle Variablen mit einem Default wert auch wenn das nicht der Fall ist.

Ja, wenn man den lauf eines programmes in 2 phasen unterteilt, dem warmup, bei dem generell der Speicherverbrauch zunimmt, und dann wenn es warmgelaufen ist, also etwa so viel speicher alloziiert wie es auch wieder frei gibt. Im warmup arbeitet man generell immer auf frischem speicher, da kann also der eindruck entstehen, sobald die software aber warm gelaufen ist, sind die initialwerte in variablen praktisch zufällig,

Wie, T1 kann nach dem Freigeben, immer noch "benutzt" werden?

Ganz einfach, Free räumt zwar den speicherbereich auf, der Zeiger steht aber immernoch in t1. Wenn ich jetzt t2 erzeuge, findet der Memory Manager den freien speicher von T1 und reused ihn. Dafür gibt es FreeAndNil, um pointer nach dem free direkt auf nil zusetzen damit sowas passiert. Andere strategien sind z.B. "du kannst kein use after free haben wenn du nie free benutzt" (klingt erst mal lustig, aber bei hoch sicherheitskritischer software bei der speicher kein problem ist wird das wirklich gemacht).

Wobei da der Pascal Memory manager noch recht sicher ist, da er ähnliche typen ähnliche speicherbereiche zuweist. Also wird zwar zwei TTests an die selbe stelle geschrieben, ein TStringList würde aber wo ganz anders landen. Der C-Memory Manager hingegen (den man via cmem benutzen kann), alloziert immer den ersten platz der groß genug ist, damit kann natürlich alles alles überschreiben. Ist durch die fragmentierung die dabei entsteht aber weniger speichereffizient und weniger sicher als der Pascal Memory manager, dafür etwas schneller.

Lambdas habe ich schon öfter gehört jetzt. ich muss mal schauen, was damit genau gemeint ist.

Anonyme funktionen. Z.B. ein beispiel aus java um eine Liste von Foo zu einer Liste von Bar umzuwandeln:

Code: Alles auswählen

fooList.map(foo -> (Bar)foo);

Die funktion map nimmt eine funktion entegen, wendet die auf jedes element an, und packt die daraus resultierenden ergebnisse in eine neue liste. Als funktion habe ich hier das lambda übergeben was ausgeschrieben so aussehen würde:

Code: Alles auswählen

Bar toBar(Foo foo) { return (Bar)foo; }

Grade für solche sachen ist das echt praktisch. Zusammen mit der idee Funktionen als Objekte benutzen zu können, hat C++ mit seinen Templates ein ganz nettes system eingeführt. Eine sortierte liste ist std::set<Typ, Komperator>. Man kann also über den Generischen Parameter Komperator eine Funktion als Klasse übergeben, die dann die Compare funktion definiert. Im gegensatz zu dem event gesteuerten verfahren in Lazarus (mit onCompare-Event) passiert das alles zur Kompilezeit und kann optimiert werden.

Aber man kann mit lambdas auch genauso gut schweinereien betreiben:

Code: Alles auswählen

std::function foo;
...
  foo();
...
  int i = 0;
  foo = [&] { i++; }
 


Wenn man jetzt foo aufruft, kann man auf das i zugreifen was an einer ganz anderen stelle steht (eventuell die lokale variable einer funktion ist). Ich denke es ist offensichtlich das man damit sehr unleserliche code erzeugen kann

Ob, es gut ist, in eine "Alte" Sprache solche gewaltigen Eingriffe zu machen, ist natürlich Fraglich.

Du darfst nicht vergessen, C++ ist standardisiert, d.h. wenn du keine lust auf Standard C++11 hast kannst du immernoch C++98 benutzen. Das ist immernoch standardisiert, und wird noch von allen großen Compilern unterstützt. Genauso kannst du immernoch den meisten alten code benutzen, es gilt nur als unschön in modernen Projekten alte Pradigmen zu nutzen. Das C++ gremium wird nur sehr selten tatsächlich sachen aus der sprache entfernen.

Wobei Rust, natürlich auch auf alte "Paradigmen" basiert, jedoch mit neuen Varianten.

Technisch gesehen sind viele der neuen ideen auch schon mehrere jahrzente alt und kommen oft mals aus der funktionalen Programmierung wie Haskell. Übrigens ne geile sprache wenn man mal was ganz anderes sehen will. Hier mal quicksort in haskell

Code: Alles auswählen

quicksort [] = []
quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
    where
        lesser = filter (< p) xs
        greater = filter (>= p) xs


Genau. Ich finde Pascal im gegensatzt zu C oder auch zu Rust, deutlich einfacher zu Lernen, weil es eben auch mehr in Deutsch gibt und es ändert sich nicht so Rasant. Das kann ein Nachteil sein, aber ich denke, es ist mehr ein Vorteil.

Ja vor allem ist Pascal ein sehr einfacher Zugang für alte Turbopascal entwickler (Siehe userbases in diesem Forum). Das ist ähnlich wie bei Java, an der sprache selbst ändert sich kaum was, was es erlaubt alten pascal entwicklern auf moderne plattformen (wie lazarus oder Rad Studio) umzusteigen. Das ist auch eine qualität, und so wie ich das sehe der hauptgrund warum pascal eben nicht modern sein will

pluto
Lazarusforum e. V.
Beiträge: 7178
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von pluto »

Die funktion map nimmt eine funktion entegen, wendet die auf jedes element an, und packt die daraus resultierenden ergebnisse in eine neue liste. Als funktion habe ich hier das lambda übergeben was ausgeschrieben so aussehen würde:

interessant ! Du kannst in Java, als Parameter eine Funktion übergeben, die dann ein "Objekt" wird oder wie?

Technisch gesehen sind viele der neuen ideen auch schon mehrere jahrzente alt und kommen oft mals aus der funktionalen Programmierung wie Haskell.

Das habe ich auch schon öfter gehört. Haskell hatte wohl einige gute Ideen, was das angeht.

Ja vor allem ist Pascal ein sehr einfacher Zugang für alte Turbopascal entwickler (Siehe userbases in diesem Forum). Das ist ähnlich wie bei Java, an der sprache selbst ändert sich kaum was, was es erlaubt alten pascal entwicklern auf moderne plattformen (wie lazarus oder Rad Studio) umzusteigen. Das ist auch eine qualität, und so wie ich das sehe der hauptgrund warum pascal eben nicht modern sein will

Es gab schon einige Entwicklungen, gerade was das Grafik System in der FCL anging, aber dass hatte natürlich nichts mit der Sprache an sich zu tun.
Es wäre schon Praktisch, wenn einiges von den Modernen Sprachen übernommen werden könnte. Z.B. Jeder Variable hat immer ein Default Wert und wird am Ende der Funktion auch frei geben, eben da wo die Gültigkeit verloren geht.
Dafür könnte es ja den Modus: Modern geben...

Ich nutzte z.b. kein Debian(außer auf mein Root-Server), weil Debian einfach zu "Alt" ist, wenn es neu Raus kommt. Aber ich nutzte Object Pascal, weil es eben "Alt" ist und Stabil läuft. Schon ein Widerspruch an sich....
MFG
Michael Springwald

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

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von Warf »

pluto hat geschrieben:interessant ! Du kannst in Java, als Parameter eine Funktion übergeben, die dann ein "Objekt" wird oder wie?


Ja du kannst praktisch Funktionen wie normale variablen betrachten, und lambdas als Initialisierung. Eine funktion mit einem Lambda aufzurufen ist also nichts anderes als eine Funktion die einen string entgegen nimmt mit "Hallo welt" oder einem anderen String literal aufzurufen.

Das habe ich auch schon öfter gehört. Haskell hatte wohl einige gute Ideen, was das angeht.

Ja ist sehr nah an der formalen Mathematik und hat die Idee das du beschreibst was du willst, nicht wie es getan werden soll. Deshalb ist das quicksort nur 3 zeilen lang, während eine technische implementierung mit der erstellung von subarrays, wahl des pivot elements, etc. in einer imperativen sprache wie pascal duzende zeilen brauchen würde

Es gab schon einige Entwicklungen, gerade was das Grafik System in der FCL anging, aber dass hatte natürlich nichts mit der Sprache an sich zu tun.
Es wäre schon Praktisch, wenn einiges von den Modernen Sprachen übernommen werden könnte. Z.B. Jeder Variable hat immer ein Default Wert und wird am Ende der Funktion auch frei geben, eben da wo die Gültigkeit verloren geht.
Dafür könnte es ja den Modus: Modern geben...

Ich nutzte z.b. kein Debian(außer auf mein Root-Server), weil Debian einfach zu "Alt" ist, wenn es neu Raus kommt. Aber ich nutzte Object Pascal, weil es eben "Alt" ist und Stabil läuft. Schon ein Widerspruch an sich....

Debian ist ja nicht nur alt in dem sinne das sich da nichts ändert, es ist auch alt in dem sinne das die aktuellste LLVM version auf debian stable auch mittlerweile 4 jahre alt ist oder so. Pascal bekommt man wenigstens ein paar neuerungen, auch wenns keine grundlegend neue technologien sind.

Ich finde es gibt ein paar sachen die sich Pascal von C++ abschauen könnte. Z.B. stack objekte deren destruktor automatisch aufgerufen wird. Allein damit könnte man wahrscheinlich schon die meisten Speicherzugriffsfehler vermeiden

pluto
Lazarusforum e. V.
Beiträge: 7178
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von pluto »

Ja du kannst praktisch Funktionen wie normale variablen betrachten, und lambdas als Initialisierung. Eine funktion mit einem Lambda aufzurufen ist also nichts anderes als eine Funktion die einen string entgegen nimmt mit "Hallo welt" oder einem anderen String literal aufzurufen.

Das macht wohl Rust mit dem Rückgabe Wert von Funktionen. Das kann eine "Fehlermeldung" sein oder der gewünschte Rückgabewert. Das nennt sich dort glaube ich Options oder so ähnlich.

Ich finde es gibt ein paar sachen die sich Pascal von C++ abschauen könnte. Z.B. stack objekte deren destruktor automatisch aufgerufen wird. Allein damit könnte man wahrscheinlich schon die meisten Speicherzugriffsfehler vermeiden

Nicht nur das: die Case Anweisung z.b. von Pascal ist deutlich Sinnvoller als die von C.
MFG
Michael Springwald

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

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von Warf »

pluto hat geschrieben:Nicht nur das: die Case Anweisung z.b. von Pascal ist deutlich Sinnvoller als die von C.

Zum teil, das C case entspricht ziemlich genau einer Assembly Sprungtabelle. Wenn du also sehr low level arbeitest, z.B. in nem Betriebsystem kernel, einem Emulator/Simulator, etc. ist das C switch case deutlich angenehmer. Auf einer hochsprachenebene hat das aber mMn. nichts zu suchen

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

Re: Konvertierung von C/C++ nach Pascal/Lazarus?

Beitrag von Timm Thaler »

Warf hat geschrieben:Wenn du das programm oben austestest sollte das folgende geschehen...


Dass der Compiler dabei ein "Warning: Local variable "a" does not seem to be initialized" wirft, hast Du großzügig übersehen.

Und ja, es passiert genau was ich erwarte. Natürlich ist der Wert der Variable undefiniert, das sagt auch der Compiler. Dennoch steht ein gültiger Wert drin, und nicht ein "NaN", es wirft keine Exception oder was auch immer oben suggeriert wurde:

pluto hat geschrieben:Der Boolean Datantypt: Wenn man ihn nicht mit einem Wert belegt, ist er weder True noch False.


Boolean ist entweder false (Null) oder true (nicht Null).

Tipp für Dich:

Code: Alles auswählen

var
  a : integer = 0;


Und schon hat a bei jedem Aufruf einen definierten Anfangswert.

Aber aufpassen:

Code: Alles auswählen

const
  a : integer = 0;


Macht aus a eine "static" Variable, also eine Variable, die ihren Wert zwischen den Prozeduraufrufen behält. Klingt komisch, ist aber so.

Ja, es gibt bei Pascal einige Inkonsistenzen, die es schon seit Jahrzehnten mit sich herumschleppt. Die wird es wohl auch nicht loswerden.

Antworten