![]() |
Delphi-Version: 10 Berlin
Delphi Unit (Language Binding) für eigene C-Lib - Umsetzung
Hallo zusammen,
ich erstelle grade Delphi Header für eine von mir in C geschriebene Library. Die technische Umsetzung ist kein Problem, allerdings stellen sich mir einige Fragen bezüglich des Code-Designs / der Organisation der Klassen:
Dann zur Aufteilung der Klassen. Die C-Lib hat 3 große Module (nennen wir sie A, B, C) und jedes Modul beinhaltet mehrere Typen und Klassen, welche ich in unterschiedliche Header-Files aufgeteilt habe. In C ist das kein Problem, da ich alle diese Header in einem "Main-Header" zusammenfassen kann, so dass der User letztlich nur diese eine Datei inkludieren muss. Bei Delphi ist das natürlich anders.
Lasst mal eure Meinung hören! Viele Grüße Zacherl |
AW: Delphi Header für C-Lib - Umsetzung
zu 1:
- fände es gut, wenn die LowLevel Umsetzung sich möglichst nah am 1:1 Prinzip orientiert, denn: - die CLIB Sachen setzt entweder der ein, der sie von C "so" kennt - oder jemand ohne viel C-Erfahrung portiert einen C-Source wo ja auch die Urform verwendet wird - wer in Delphi eine "optische" Kapselung will, kann ja den NameSpace stets mit davor schreiben... ala clib.atoi('123') - eine Delphi OPP Schicht zur unterstützung von SprachFeatures kann für Step 2 und Leute mit Delphi&C Erfahrung nicht schaden, ist aber dann nicht mehr rückwärtsprotabel, ausser es man erstellt gleiches auch als logisch kompatibel gleich mit in CPP zu 2: - für pure 1:1 Portierung wäre es im Prinzip egal, weil wer C Quellen 1:1 umsetzt, sieht dort ja die "Header includes", kaönnte die also 1:1 als "Delphi uses" übernehmen, ABER in C ist die Reihenfolge fast wurcsht und man hat dort oft mehr include als nötig, denn es wird zur Vermeidung von "mehrfachen Defines/Typen/..." einfach in den Headern stets gefragt, ob das Defines des HeaderFiles noch nicht definiert is, dann wird es "einmal" definiert und alles nötige gamacht. Bei den nächsten 100 includes passiert dann nix mehr.. das ist in C & CPP ja so üblich, da streikt aber das Konzept der DelphiUses im InterfaceTeil und kann nur per Trick und viel Mühe im Einzelfall durch "ImplemenationUses" von Kreuzreferenzen befreit werden... -> also besser alles LowLevel in EINE CLib unit (auch wenn das den DelphiLinker dazu verleitet die EXE mit vielen wohl ungenutzten Sachen etwas aufzublähen. -> ein CLIB.INC Files, welches im InterfaceTeil bei uses einfach per include eingebunden wird, hält die Option offen, es später doch in mehrere .pas Units aufzuteilen, da aber nur C Kenner wissen, was sich in welcher UNIT/Header, wäre dies Option mehr der Ansatz für C Spezialisten, sich hier ihre eigenen Sachen "zentral" mit einzu binden CLIB4PAS klingt definitiv interessant! Hatte vor Jahren mal für 100T Pas-VCL-CodeZeilen sowas rückwärts gemacht, also quasi ne echte CPP VCL gemäß der CPP Header vom C++Builder relalisiert, damit man auch in VC z.B. eine VCL Stringlist, TList,... oder einen VCL (C)AnsiString hatte... das hat mir damals bei der schnellen ersten Version einer PAS->CPP Portierung eines guten PAS BackEnd Frameworks sehr geholfen. Den so generalisierten Ansatz wie du jetzt hier planst habe ich selbst nie gemacht, beim manuellen C->PAS Convert nutze ich nur eine eigene PAS unit, wo ich eben all die Dinge über die zeit so rein genommen haben, welche ich in meinen C Quellen eben so verwende:) |
AW: Delphi Header für C-Lib - Umsetzung
Hey hey, erstmal danke für deine Antwort!
Ich glaube allerdings wir reden ein wenig aneinander vorbei :) Meine Frage bezieht sich auf eine ganz konkrete Library (die ich in C geschrieben habe) und nicht die C-Runtime Lib (habe mal versucht den Titel etwas eindeutiger zu gestalten). Einige Ansätze aus deiner Antwort kann ich allerdings trotzdem übernehmen. Das Verwenden von .inc Files ist auf jeden Fall eine gute Idee, mit der ich mein C-Header-Konzept beibehalten könnte, trotzdem aber auf Delphi Seite nur eine Unit hätte. Vermutlich werde ich so vorgehen, dass ich eine Low Level Implementierung unter dem Namen
Delphi-Quellcode:
oder einfach nur
MyLib.API.pas
Delphi-Quellcode:
erstelle, welche die kompletten Funktionen und Datentypen der C-Lib bereitstellt. Zusätzlich kann ich dann noch die Units
MyLib.pas
Delphi-Quellcode:
,
MyLib.ModuleA.pas
Delphi-Quellcode:
und
MyLib.ModuleB.pas
Delphi-Quellcode:
erstellen, welche dann jeweils die Kapselung der 3 Module in richtigen (Wrapper-)Klassen bereitstellt.
MyLib.ModuleC.pas
|
AW: Delphi Unit (Language Binding) für eigene C-Lib - Umsetzung
Jupp, im Prinzip stimme ich mit dem Überein, was schon mein Vorredner sagte.
Theoretisch kann man Methden von Klassen auch direkt external mit Prozeduren verlinken, aber in der Prakis hat es sich bewährt erstmal die API möglichst 1:1 nach Pascal zu übersetzen, somit kann diese Schnittstelle erstmal genauso verwendet werden, wie es die Dokumentation und die vielen C-Beispiele zeigen (wenn man eine bekannte C-Lib übersetzt). Allerdings passe ich die Namen der Parameter öfters mal an (mehr Delphi-Style und entferne Prefixe). Auch Typen passe ich dem Delphi-Style an, so lange es möglich ist, wie z.B. Integer statt INT oder VAR statt Pointer. Sogar Const-String statt PChar ist oftmals möglich, bei IN-Parametern, aber lohnt sich nur, wenn sowas bei allen Prozeduren möglich ist, da mit sich möglichst alles an einen "einheitlichen" Style hält. Wenn direkt als Klasse, dann aber möglichst nah an der originalen API. (Benamung) Wie gesagt, so kann man die API "auch" im Original-Style verwenden und vorallem ist es so einfacher später neue Verionen der API einfließen zu lassen. Falls ich Zeit hab, dann würde ich das Ganze dann nochmal in "schönere" Klassen/Interfaces mit "verständlicheren" Methodennamen kapseln (Wrapper), bzw. kleinere spezialisiertere, minimalistische und einfache Komponenten. |
AW: Delphi Unit (Language Binding) für eigene C-Lib - Umsetzung
Ich würde es auch eher 1:1 umsetzen, allein schon wegen der Wartbarkeit und lesbarkeit.
Allerhöchstens wenn A, B, C trivial sind würde ich das in eine Unit nehmen, aber das wäre meiner Meinung nach etwas schlechter Stil, weil A, B, C sicherlich auch verschiedene Aufgaben haben. Diese Aufgabentrennung sollte man am Besten auch in Delphi 1:1 abbilden. Rollo |
AW: Delphi Unit (Language Binding) für eigene C-Lib - Umsetzung
Zitat:
Zitat:
Delphi-Quellcode:
geprefixt, CamelCase Schreibweise und
T
Delphi-Quellcode:
bzw.
var
Delphi-Quellcode:
für Pointer. Zusätzlich habe ich für einige Enums noch Helper Methoden wie z.b.
const
Delphi-Quellcode:
implementiert (dafür hat die C-Lib jeweils eine exportierte Funktion).
ToString
Zitat:
Danke euch allen! :?: Noch irgendwelche Tipps zum Lösen von Namenskonflikten die auftreten, wenn ich zusätzliche Wrapperklassen schreibe? Habe in C ja meine Context-Structs wie z.b.
Delphi-Quellcode:
, die ich dann erstmal 1:1 nach Delphi als
MyDecoder
Delphi-Quellcode:
umsetze. Die Wrapperklasse kann ich jetzt natürlich nicht auch
TMyDecoder = record
Delphi-Quellcode:
nennen. Hier lieben den Namen der Wrapperklasse mutieren (
TMyDecoder
Delphi-Quellcode:
oder sowas) statt Den des Records? Oder doch liebe den Record umbenennen in z.b.
TMyDecoderWrapper
Delphi-Quellcode:
und dafür die High-Level Klasse bei
TMyDecoderStruct
Delphi-Quellcode:
belassen?
TMyDecoder
:?: Achso und würdet ihr Klassen, Typen, Records, Konstanten, etc. mit dem Namen der Lib prefixen? Mangels Namespaces mache ich das eigentlich ganz gerne in Delphi (auch wenn man Mehrdeutigkeiten natürlich mit explizitem Angeben der Unit lösen kann - was aber auch irgendwie nichts Ganzes und Halbes ist). |
AW: Delphi Unit (Language Binding) für eigene C-Lib - Umsetzung
Zur Namensgebung und als Alternative, wo man in C das simpel per Groß/Klein-Schreibung macht:
TMyTool verwende ich in Delphi nur für "echte" Klassen/Objekte, also alles was man per CreateAufruf erzeugen muss RMyTool verwende ich in Delphi für Records, also C Structs, welche sich auch statisch ohne "Create" nutzen lassen PMyTool definiere ich immer zusammen mit RMyTool als typisierten Pointer von RMyTool Mit Operatoren und Propertys für Records also "R..." habe seit D2007 sehr gute Erfahrungen mit allen weiteren Delphi Varianten. Ich nutze insbesondere die "default" Property oft als typisiertes virtual Array/List... funktioniert seit D2007 super und ersetzt mit die doofen TList<XY> Generics die zwar schön einfach zu tippen sind, aber bei mir schlicht zu langsam und zu instabil sind. Präfixe: - auch wenn OldScool: ich mache es auch heute noch - allgemeines wie ein GetValue, ein UpdateStorage oder UpdateGUI sind aus meiner Sicht "ohne Kontext" sehr schlecht im Code zu verstehen... daher lieber mylibGetValue, mylibUpdateXXX - ich ziehe das trotz der paar Zeichen Zusatztiparbeit so durch, hat den positiven neben Effekt, das fremde in der Anwendung auch stets sofort sehen&wissen in woher das kommt und bei bedarf dort finden, wozu das ist und was es macht Wer nur mit allgemeingültigen Interfaces ala "WriteData" arbeiten will, der soll es tun und kann es sich selbst HighLevel so definieren. Ich bevorzuge bei LowLevel und ExternalModule einer kurze 1:1 PräfixVariante, welche bei mir auch so schon im C Source vorhanden ist:) |
AW: Delphi Unit (Language Binding) für eigene C-Lib - Umsetzung
Zu a:
Ich würde sie erstmal 1 zu 1 umsetzen und dann darauf aufbauend eine entsprechende Klassenhirarchie aufbauen. Eine Funktions-Lib in eine Klassenhirarchie zu packen, nur damits OOP-Konform ist, macht keinen Sinn und erzeugt i.d.R. nur Overhead. Zu b: Hier würd ich zu 1. tendieren. Damit erleichtert man die Orientierung, sowohl im Source, als auch ggf. in der Dokumentation. |
AW: Delphi Unit (Language Binding) für eigene C-Lib - Umsetzung
Zitat:
Delphi-Quellcode:
Prefix für sämtliche Typen vorsieht. Allerdings sehe ich
T
![]()
Delphi-Quellcode:
Prefix und vollständig in Capslock) deklariert wurden und danach nochmal ein Alias mit
T
Delphi-Quellcode:
Prefix und CamelCase angelegt wurde.
T
Zitat:
Zitat:
Delphi-Quellcode:
, etc), sind also perfekt in Klassen zusammenfassbar.
ModuleAInit, ModuleAMachWas, ModuleASetThis, ModuleAGetThat
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:04 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz