DEUTSCHE VERSION |
|
Links | | | Forums | | | Comments | | | Report news |
Chat | | | Polls | | | Newsticker | | | Archive |
amiga-news.de Forum > Programmierung > C oder C++? | [ - Search - New posts - Register - Login - ] |
-1- 2 3 4 5 | [ - Post reply - ] |
2010-04-28, 10:53 h Der_Wanderer Posts: 1229 User |
Hallo! Ich portiere gerade etwas Code von Amiblitz nach C (oder C++), damit ich es unter Windows/Linux etc. nutzen kann. Ich möchte den C Code aber auch auf dem Amiga weiterhin nutzen können. Ist das problematisch, wenn ich C++ benutze, oder sollte man sich lieber an plain C halten? C++ hat einige Vorzüge, die ich gerne nutzen würde. Wenn ich damit aber auf dem Amiga in Teufels Küche komme, dann mache ich das lieber strikt in C. Momentan habe ich auf dem Amiga GCC 2.x installiert, und würde ungern an der Install rumpfuschen müssen. Wenn ich C++ sage, dann meine ich nicht exzessiv mit OOP, Templates, STL etc., sondern lediglich simple Dinge wie Referenzparameter etc. Der Unterschied zu plain C ist also nicht gross. Sorry, wenn die Frage etwas dämnlich ist, aber auf dem Amiga hab ich mit C kaum Erfahrung. -- HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ - Answer - Quote - Direct link - ] |
2010-04-28, 12:07 h Kaesebroetchen Posts: 643 User |
@Der_Wanderer: C++ am Amiga geht durchaus. Was oft ein Problem darstellt sind z.B. MUI Makros die vom Namen her einen Konflikt zu diversen Methoden von STL Klassen darstellen. Also Dinge wie set() get() usw. Das kann man aber eigentlich immer mit #undef usw. auflösen. Richtig nervig sind Linker Probleme. Da werden oft Symbole nicht gefunden weil der Linker für C++ irgendwie anders arbeitet also für C. Das kann man dann wiederum mit extern "C"{#include ...} hinbiegen. Das kann aber schon mal nervtötend sein. Ein paar Anregungen für C++ Amiga Code: ZUNE Text Editor Beispiel Murks IDE (lässt sich auch für 68k kompilieren) Ich hoffe das hilft dir ein wenig. Die richtigen Experten für das Thema C++ und Amiga API findest du auf #aros die sind in aller Regel auch sehr nett und hilfsbereit. -- http://amidevcpp.amiga-world.de/ [ - Answer - Quote - Direct link - ] |
2010-04-28, 12:11 h whose Posts: 2156 User |
@Der_Wanderer: Deinen Angaben nach zu schließen solltest Du mit C++-Code genauso glücklich werden können wie mit C-Code. Ich nehme nicht an, daß Du gcc2.7 oder was ähnlich vorsintflutliches installiert hast, oder? Mit z.B. 2.95.2 oder höher könntest Du auch "härtere" Geschichten relativ problemlos übersetzen, von daher mußt Du Dir wohl keine Sorgen machen. -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Answer - Quote - Direct link - ] |
2010-04-28, 14:00 h Der_Wanderer Posts: 1229 User |
In dem Code sind erstmal keinerlei OS Abhängigkeiten drin. Das einzige was ich brauche ist Datei I/O und Speicher allocieren. Normalerweise verwende ich dafür fopen/fclose etc. und malloc. Mit #ifdef WIN32 oder #ifdef AMIGA will ich sparsam sein, am besten gar nicht. Ich verwende auch keinerlei Libraries oder andere externe Anhängigkeiten, wie STL. Wie schon erwähnt, kommt der Code von Amiblitz. Das entspricht eher C. Nur die Strings machen mir etwas Kopfschmerzen. Dafür habe ich eine kleine String Include geschrieben, die aber C++ feature nutzt, wie z.B. Refernzübergabe dass man nicht mit Pointer arbeiten muss. z.B. code:/* free a string */ void str_free(str &string) { if (string) { free(strH(string)); string=NULL; } } Geht das unter Amiga ohne Probleme? Ich möchte auch keine rießen Makefile Orgien, damit kenne ich mich gar nicht aus. Unter Windows benutze ich Visual Studio, da wird man von sowas gottseidank verschont. Am Ende soll das auf dem Amiga eine Shared Library werden. Unter Windows eine DLL. GCC habe ich gcc version 2.95.3. Wenn ich C++ nehme, dann sollte ich am besten alle source files C++ machen und nicht mischen, oder? Unter VS ist das kein Problem, aber "per Hand" wäre das wohl komplizierter zu linken(?). -- HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ Dieser Beitrag wurde von Der_Wanderer am 28.04.2010 um 14:04 Uhr geändert. ] [ - Answer - Quote - Direct link - ] |
2010-04-28, 15:20 h whose Posts: 2156 User |
Zitat: Da gabs noch nie Probleme, wenn Du die Standard-Klamotten verwendest, selbst mit StormC 3 nicht. Zitat:code:/* free a string */ void str_free(str &string) { if (string) { free(strH(string)); string=NULL; } } So triviale Sachen gehen ohne Probleme, wie gesagt, selbst unter Storm in der Uralt-Version. Zitat: Spätestens hier setzt dann die #ifdef/makefile-Orgie ein... Zitat: Hängt davon ab, wie Du das compilierst. Schau Dir mal die Doku zu gcc/g++ an. Da findest Du auch einiges über das "Mischen" von Code und die Linkerproblematik. -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Answer - Quote - Direct link - ] |
2010-04-28, 15:35 h Der_Wanderer Posts: 1229 User |
Ich kann mich erinnern, als ich mal eine Library compiliert habe, dass es Probleme mit fopen, printf etc. gab, irgendwas mit libnix in der Commandozeile war notwendig. Ist aber lange her, letztendlich hatte ich alles über AmigaOS API gemacht, aber das will ich eigentlich vermeiden. Ich habe nun erstmal alles als C++ angelegt. ich hoffe das rächt sich nicht irgendwann... -- HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ - Answer - Quote - Direct link - ] |
2010-04-28, 15:46 h Holger Posts: 8116 User |
Zitat:Wenn das alleine ausgereicht hatte, hattest Du nur verdammt viel Glück (Bzw. nicht ausreichend getestet). Die C-Funktionen sind grundsätzlich nicht für den Einsatz in einer Amiga-Bibliothek geeignet, es sei denn der Autor der spezifischen Version weist ausdrücklich auf eine solche Eignung hin. Zitat:Wenn es eine Amiga-Bibliothek werden soll, wirst Du nicht um Amiga-spezifischen Code herumkommen. -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2010-04-28, 15:58 h Der_Wanderer Posts: 1229 User |
@Holger: > Wenn das alleine ausgereicht hatte, hattest Du nur verdammt viel Glück nein, hats ja nicht. Deshalb musst ich alles über AmigaOS API machen. (file I/O etc.) > Wenn es eine Amiga-Bibliothek werden soll, wirst Du nicht um Amiga-spezifischen Code herumkommen. Ist mir klar. Es macht aber einen unterschied, ob ich nur ein Frontend für die Library davor setzen kann sowas wie "amigalib_main.cpp" oder ob ich meinen kompletten Code kontaminieren muss. Immerhin habe ich den Filezugriff in ein Modul verbannt, sodass ich nur dort #ifdef AMGIA machen müsste. Aber schön ist das ganze natürlich nicht. @whose > So triviale Sachen gehen ohne Probleme, Also laut Holger geht das dann wohl doch nicht ohne Probleme? -- HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ - Answer - Quote - Direct link - ] |
2010-04-28, 16:40 h akl Posts: 265 User |
@Holger: >Die C-Funktionen sind grundsätzlich nicht für den Einsatz in einer >Amiga-Bibliothek geeignet Das hängt davon ab, welchen Compiler mit welcher C-Laufzeitumgebung man nutzt, welche Funktionen man davon nutzt und ob und wie man sicherstellt, dass der Code "threadsafe" bleibt. So verallgemeinert ist die Aussage nicht richtig. [ - Answer - Quote - Direct link - ] |
2010-04-28, 17:47 h whose Posts: 2156 User |
Zitat: Erst, wenn Du das in eine Amiga shared library "verpflanzt". Aber auch hier gilt, was akl schon ausführte. Kurz gesagt: "Hängt davon ab" Ich dachte, es ginge erst einmal primär um das Funktionieren dieses Codes an sich, ohne Spezialitäten wie "ich bastel eine Amiga shared library daraus". Dazu habe ich aber auch was gesagt Spätestens, wenn Du eine shared library/DLL daraus machen willst, wirst Du um die #ifdef/makefile-Orgien nicht herum kommen. Das geht ja schon bei Dingen los, die erst einmal gar nichts mit Deinem Code zu tun haben, Init usw. Bei Libraries, die systemabhängig sind, gibt es eigentlich immer Probleme mit den Funktionen der C-Linker-Library, sofern diese bestimmte Voraussetzungen nicht erfüllt. Es gibt Gründe für die "Erfindung" von clib2/newlib und wie sie alle heißen... -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Answer - Quote - Direct link - ] |
2010-04-28, 21:01 h Holger Posts: 8116 User |
Zitat:Du hast ja auch die Aussage verallgemeinert, in dem Du sie aus dem Zusammenhang gerissen, und den einschränkenden Teil "es sei denn der Autor der spezifischen Version weist ausdrücklich auf eine solche Eignung hin" unterschlagen hast. Dass es um stdio und real existierende Amiga-Compiler ging, war eigentlich auch klar. -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2010-04-29, 17:04 h Der_Wanderer Posts: 1229 User |
Also, darf ich nun "sprintf" oder "fopen" in einer Shared Lib benutzen oder nicht? Sieht so aus, als bräuchte ich dafür eine spezielle Runtime Linkerlib. Nachtrag: Unter Windows und Linux scheint das kein Problem zu sein. Haben dort die DLLs/SOs für jede offene Instanz eigene Addressräume, und die Funktionen müssen deshalb nicht thread-safe sein? Oder ist die Amiga Implementation der C-Runtime einfach crappy? -- HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ Dieser Beitrag wurde von Der_Wanderer am 29.04.2010 um 17:45 Uhr geändert. ] [ Dieser Beitrag wurde von Der_Wanderer am 29.04.2010 um 17:46 Uhr geändert. ] [ - Answer - Quote - Direct link - ] |
2010-04-29, 19:06 h Holger Posts: 8116 User |
Zitat:sprintf könnte vielleicht noch funktionieren, von fopen würde ich die Finger lassen. Zitat:Ob die Funktionen thread-safe sind oder nicht, ist noch mal eine eigene Baustelle. Allgemein lautet die Antwort auf Deine erste Frage ja, die dynamisch geladenen Bibliotheken verhalten sich auf diesen Systemen kaum anders als zum Programm statisch gelinkte Bibliotheken. Der (read-only) Programmcode wird zwar geteilt, alle Variablen existieren aber jeweils pro Prozess. Das heißt aber nicht zwangsläufig, dass die jeweilige Bibliothek noch korrekt arbeitet, wenn dieser Prozess mehrere Threads erzeugt und die Funktionen von mehreren Threads aus aufruft. -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2010-04-29, 19:06 h jolo Posts: 110 User |
@Der_Wanderer:Zitat: Nee, eigentlich sind beide Funktionen tabu. Eigentlich deshalb, weil es bestimmt irgendwo Implementierungen geben wird, die dies erlauben. Mir ist aber persönlich nur eine bekannt, die allerdings eine Close-Sourced Version für ein kommerzielles Programm ist. Wird Dir also nicht helfen. Standard-IO-Funktionen basieren immer auf einen Compiler-spezifischen Startup-Code; da eine Shared-Library keinen Startup-Code enthält, entfallen diese Funktionen. Zudem sind diese Standard-IO-Funktionen nicht reentrant, meist noch nicht mal thread-safe, so dass sie sowieso nicht verwendet werden dürfen. Bei sprintf() musst Du sehr vorsichtig sein. Es gibt Implementierungen, die malloc() und free() verwenden, wobei diese beiden Funktionen wiederum auf den Startup-Code aufbauen. Also sind grob gesagt alle Funktionen die beim Beenden des Programmes automatisch Ressourcen zurückgeben, nicht reentrant und dürfen daher nicht in einer Shared-Library Verwendung finden. Zitat: Du vergleichst zwei verschiedene Paar Schuhe. Unter AmigaDOS sind Prozesse wirklich eigenständig, unter Linux/Windows wirst Du wohl kaum einen echten Prozess initiieren sondern einen Task/Thread starten, der von einem Prozess verwaltet wird. Dementsprechend kann ein Task/Thread auf Ressourcen zugreifen, die der übergeordnete Prozesses bereitstellt. Beim Amiga gibt es keinen übergeordneten Prozess, also ist der Prozess selber zuständig für das Heranschaffen von Informationen. Beim Amiga erledigt dies der Startup-Code. Zudem können DLLs oder Shared Objects auf die gleichen Funktionen, die ein Task/Thread benutzt, zurückgreifen, was beim Amiga (OS3.x) unter Verwendung von Shared-Libs nur mittels Pointer-Akrobatik durchgeführt werden kann und nicht zu empfehlen ist, da dann eine Shared-Lib bestimmte Funktionen seitens des Prozess voraussetzt. Auch solltest Du nicht außer acht lassen, dass eine Shared-Lib weder ein Prozess, noch ein Amiga-Task ist, sondern nur eine Ansammlung von Routinen darstellt, die von mehreren Prozessen/Amiga-Tasks gleichzeitig benutzt werden können, was beinhaltet, dass diese Funktionen reentrant sein müssen und nicht nur thread-safe. Anbei, unter AmigaDOS ist C++ ungeeignet zum Erstellen von Shared-Libs. C++ ist für komplexere, größere Applikationen die bessere Wahl wobei Treiber, und dazu gehört eine Shared-Lib, mittels C erstellt werden sollten, denn dafür ist C entwickelt worden. Noch generiert ein C++-Compiler programmiert in C++ nämlich keinen thread-safe Code. Man kann, wenn man die Compiler Interna kennt, dies auch mittels C++ bewerkstelligen, aber das impliziert, dass man ausschließlich diesen einen C++-Compiler verwendet. Übertragbarkeit auf einen anderen C++-Compiler ist damit hinfällig. Grüße [ - Answer - Quote - Direct link - ] |
2010-04-29, 22:04 h Der_Wanderer Posts: 1229 User |
Hm, das wird komplizierter als ich dachte. Soll ich nun doch besser C nehmen? Also wenn ich mich zusammenreise, dann komme ich mit fopen() fread() fwrite() fseek() ftell() fclose() malloc() free() aus. Wobei Konsole Output schon hilfreich wäre, also printf(). Alles andere ist rein algorithmisch und kann re-entrant oder zumindest thread-safe implementiert werden. Wenn das nicht geht, wird es schwierig. Wenn ich für diese Funktionen AmigaOS API nehmen würde, dann sollte es doch eigentlich funktionieren, oder nicht? Also Open() Read() Write() Seek() Close() Allocmem()/Allocvec() Freemem()/Freevec() Was hat man denn in der C Runtime "verbrochen", dass es nicht mehr thread-safe ist? Bei printf() kann ich das noch verstehen, denn da müsste man sich erst den Handle auf den stdout holen. Aber die anderen Sachen sollten doch funktionieren, oder übersehe ich da etwas? -- HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ Dieser Beitrag wurde von Der_Wanderer am 29.04.2010 um 22:06 Uhr geändert. ] [ Dieser Beitrag wurde von Der_Wanderer am 29.04.2010 um 22:07 Uhr geändert. ] [ - Answer - Quote - Direct link - ] |
2010-04-29, 22:18 h Thore Posts: 2266 User |
Die AmigaOS API Funktionen sollten immer gehen, ungeachtet des Compilers (sofern inline oder andere pragmas/libcall Routinen dies ermöglichen) Es ist stark abhängig von diesen pragmas/clib/inlines und der Link-Libs ob die printf, fopen etc richtig funktionieren. Die AmigaOS API Calls hingegen sind immer gleich, da aus den Amiga Libs aufgerufen. Daher sind diese auch eher zu empfehlen. [ - Answer - Quote - Direct link - ] |
2010-04-30, 20:35 h jolo Posts: 110 User |
@Der_Wanderer:Zitat: Das bleibt Dir überlassen. Wenn Du weißt welchen Code der C++-Compiler generiert den Du verwendest, und Du ausschließlich diesen verwendest, kannst Du es mit diesem angehen. Ich persönlich würde mich aber nicht abhängig von einem C++-Compiler machen wollen; zudem ist eine Amiga Shared-Lib ein Low-Level Konstrukt und somit sollte auch C vor C++ Verwendung finden. Zitat: Vergesse printf() ganz, ganz schnell. Ich weiß nicht warum so viele Programmierer printf() innerhalb einer Shared-Lib verwenden möchten. 1) printf() ist nicht thread-safe; es arbeitet intern mit Puffern und Variablen auf Dateiebene (global). 2) das AmigaDOS erlaubt es nicht, dass Prozesse File-Handles untereinander austauschen; jeder Prozess ist angehalten, die File-Handles per Instanz zu reservieren und wieder freizugeben. 3) printf() setzt zwingend einen Startup-Code voraus; dieser entfällt beim Schreiben einer Amiga-Shared-Lib. 4) printf() ist eine C-Funktion, unter C++ ist das Äquivalent 'cout'. (SCNR ) Wenn Du die Ausgaben nur zur Fehlersuche benötigst, verwende kprintf() (OS3, MorphOS, AROS) oder DebugPrintF() (OS4) und starte vorab Sushi oder Sashimi. Zitat: Es liegt bei Dir - und einzig und alleine bei Dir. Das Amiga Betriebssystem selbst offeriert seine Funktionen auschließlich in der reentranten Form. Zitat: Natürlich, sofern Du Abstand zu Funktionen die in der C-Runtime Lib stehen nimmst. Zitat: Es gibt keine Bestimmung die da lautet, dass eine C-Runtime Lib thread-safe sein müsste. Die C-Runtime Lib ist eine statische Bibliothek und wird dem Programm einfach hinzu gelinkt. Thread-safe C-Runtime Libs sind Erscheinungen die nur deshalb implementiert wurden, damit man unter UNIX und Konsorten malloc() und free() ohne Gefahr verwenden kann. Da dort die Dateihandhabung auch im Betriebssystem ganz anders gehandhabt wird wie unter AmigaDOS, kann man dort Sachen gefahrlos durchführen, die das AmigaDOS ins Schleudern bringen würden, also Threads für Dateioperationen benutzen. Beim AmigaDOS ist man gezwungen, ausschließlich den Prozess, der die Dateirechte hält, zu benutzen. Man kann keine Dateirechte einfach so auf einen anderen Prozess übertragen. @Thore: Zitat: Innerhalb einer Amiga Shared-Lib kann man auf die standardisierten C-Lib IO-Funktionen nicht zurückgreifen. Dafür müsste man nämlich Teile des Startup-Codes klonen und diesen Teil in die Lib-Init-Funktion platzieren, was aber ein Tabu ist, da diese Funktionen nicht reentrant sind. Solange nur ein Programm diese Lib benutzen würde, liefe alles noch wie am Schnürchen, nur, wenn gleichzeitig ein zweites Programm diese Lib benutzen würde, würde das Betriebssystem sofort abstürzen. Leider es ist nicht abhängig von "pragmas/clib/inlines", da diese Dateien nur Header-Dateien sind, demnach keinen realen Funktionscode beinhalten sondern nur die Prototypen und Sprungziele. Auch Stub-Funktionen (Glue-Code) würde funktionieren, falls die betreffenden Funktionen dahinter selber reentrant wären. Dies ist aber nicht gewährleistet bei Funktionen der "libnix"- oder "vc"- Runtime Libs, ganz zu schweigen von den "stream" Klassen. Die unkritischen Teile der "vc" Runtime Library sind nach Aussagen von Frank Wille die 32/64 Bit Support Funktionen, die "ctype" und die "string" Support Funktionen. Die Benutzung andere Funktionen innerhalb einer Shared-Lib kann zu Fehlverhalten führen bzw. in einem GURU enden. Und ich behaupte mal, dass das Gleiche auch für "libnix" gilt. Grüße [ - Answer - Quote - Direct link - ] |
2010-04-30, 21:11 h Der_Wanderer Posts: 1229 User |
Ok, also ich fasse zusammen: Plain C verwenden, ohne jegliche Runtime. Also absolute Askese, das habe ich befürchtet. Das lädt nicht gerade zum Entwickeln für den Amiga ein. Ich verstehe eigentlich gar nicht warum, steckt doch hinter einem fopen() letztendlich ein Open() der dos.library, was re-entrant ist. Irgendwo beim "einpacken" hat da doch jemand Bockmist gebaut. Dann werde ich wohl erstmal eine ~Amiga Version portieren. -- HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ - Answer - Quote - Direct link - ] |
2010-05-01, 01:36 h whose Posts: 2156 User |
Zitat: Was hat es denn mit Amiga zu tun, daß die C-Runtimes oftmals nicht wirklich für Systementwicklung (und zu diesem Themenbereich gehören shared libraries auch) taugen und ein ziemlicher Aufwand drumherum betrieben werden muß, damit das doch "irgendwie" funktioniert? Das Problem ist die Abhängigkeit der C-Standardfunktionen von bestimmten Kontexten des Runtime-Teils (startup code), die sich im AmigaOS halt nicht so einfach "mal eben teilen" lassen, wie schon erwähnt. Es ist dabei ziemlich unerheblich, ob zum Schluß ein Aufruf einer OS-Funktion daraus kondensiert oder ob der Entwickler der C-Runtime wirklich alles selbst macht. Die Abhängigkeit der C-Standard-Funktionen von bestimmten Kontexten ist erst auf einer höheren Ebene gegeben, nicht zwangsläufig auf Ebene des Betriebssystems. Kurz gesagt: AmigaOS kann nix dafür, daß C-Standardfunktionen so funktionieren, wie sie funktionieren Du könntest aber zum Beispiel, wenn Du für Windows schon eine DLL bauen willst, für die Amiga68k-Fassung Linker-Libraries bauen, damit umgehst Du das Problem mit den vom Startup-Code abhängigen Funktionen quasi im Spaziergang. Nachteil ist halt, daß dann jedes Programm, daß Deine Funktionen nutzt, diese im Code mitschleppen muß. Wobei das für 68k-Code nicht wirklich ein Problem darstellen dürfte, da der Code oft recht klein ausfällt. Gerade bei so simplen Funktionen wie die, die Du hier gezeigt hattest. Kleiner als die Windows-Pendants dürften die Programme daher alle Male sein Oder eben halt ein wenig #ifdef-Akrobatik und Verzicht auf printf() und Konsorten. Machbar ist das durchaus. Davon mal ab, für OS4 z.B. hat man einen den DLLs extrem ähnlichen Mechanismus eingeführt, und irgendwo ist das ja immer noch ein bißchen Amiga... -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Answer - Quote - Direct link - ] |
2010-05-01, 12:55 h jolo Posts: 110 User |
@Der_Wanderer: Es hat mich jetzt mal gerade eine Minute gekostet, um herauszufinden, dass "clib2" thread-safe ist, also das ist, wonach Du suchst. Allerdings existiert "clib2" auf Source-Forge nur für AmigaOS3/4 als Release. Wie viel Arbeit es ist diese C-Runtime Bibliothek für MorphOS/AROS anzupassen, weiß ich nicht. Anbei, nach Aussage von Illka Lehtoranta müsste "libnix" unter MorphOS thread-safe sein. Zudem ist "clib2" eine C-Bibliothek und setzt auch wieder einen Startup-Code voraus. Da ich aber irgendwo schon einmal gelesen habe, dass "clib2" innerhalb einer Amiga-Shared-Bibliothek verwendet wurde, musst Du die Dokumentation zu "clib2" lesen, um herauszufinden, welche Bedingungen dafür eingehalten werden müssen. Werfe nicht gleich die Flinte ins Korn. Zitat: Ich entwickle meine Programme lieber auf dem Amiga als unter Windows/Linux, weil ich hier hundertprozentig weiß, welche Betriebssystem-Funktionen meine Programme benutzen. Schon die Benutzung der clib- oder der POSIX-API verschleiern, welche Funktionen man tatsächlich verwendet. Beispiel gefällig? fopen() in Verbindung mit fread() wird je nach Implementierung und des Quellmediums (Floppy-Disk, Hard-Disk etc.) andere Puffer-Größen verwenden. Z.B. wird anhand des Struktureintrages "Bester Datentransfer" ("<sys/stat.h>") ein Puffer verwendet, der irgendwo im Bereich von 512 Bytes bis zu mehreren Kbytes angesiedelt ist, demnach wird fread()/fwrite() nicht exakt die Anzahl der Daten einlesen/schreiben, die Du angibst, sondern dies alles über einen Puffer im RAM bewerkstelligen, der ohne Dein Zutun alloziiert wurde. Erst wenn Du explizit diesen Puffer (Cache) leerst oder fclose() aufrufst oder auch Dein Programm beendest, werden Daten geschrieben. Beim Lesen ist es wiederum anders. Du kannst sagen ich lese Byte für Byte, intern wird aber ein Puffer verwendet, der Dateien blockweise liest, also zum Beispiel 64 Kbytes auf einmal. Liest Du das nächste Byte, wird keine Lesevorgang ausgeführt, sondern nur der Pufferzähler um ein höher gesetzt (fseek()) und Dir das nächste Byte, das sich im RAM (Cache) befindet, retourniert. Jetzt hast Du auch den Grund, warum das nicht von Anfang an thread-safe programmiert wurde. Es wurden nämlich Variabeln auf Dateiebene angelegt. Erst als man begann, den FILE-Record (FILE-Descriptor) so zu erweitern, dass diese Puffer/Zähler Teile des FILE-Records wurden, ging man den thread-safe Weg (blödes Wort, aber mir fällt nichts Besseres ein, sorry). Damit bleibt aber noch immer ein Problem bestehen. Beim Beenden eines Programmes müssen noch alle geöffneten Dateien geschlossen werden sowie alle verwendeten Speicherbereiche dem Betriebssystem zurückgegeben werden. Wie macht man das, wenn man alles im FILE-Record platziert hat, der FILE-Record aber nur dem Anwenderprogramm bekannt ist? Lösung, man erstellt eine Liste mit allen FILE-Records ohne Zutun des Anwenderprogrammes, ergo beim Aufruf von fopen()! Und wo bewahrt man den Zeiger auf diese Liste auf Dateiebene auf? Im Startup-Code! Was macht der Startup-Code wenn dessen Exit-Routine aufgerufen wird? Es testet die Liste; ist ein Eintrag nicht null, wird automatisch flcose() ohne Dein Zutun aufgerufen und damit der Pufferinhalt geleert (flush), die Datei geschlossen und die Speicherbereiche dem Betriebssystem als unbelegt zurückgemeldet! Ja, ich gebe Dir Recht, der Verzicht auf clib- oder POSIX-Funktionen beim Programmieren unter AmigaDOS (speziell 3.x) bedeutet im Umkehrschluss sehr viel mehr Arbeit, macht mich aber unabhängig von irgendwelchen Implementierungen. Zudem spielt Zeit keine Rolle für mich; bin halt ein Hobby-Programmierer. Auch solltest Du niemals außer Acht lassen, dass man unsichere Teile immer thread-safe gestalten kann, indem man *nur* die Library-Base klont, also negativ- sowie positiv-Offsets (OS3/AROS/MorphOS, OS4 ist ein wenig *anders*), und jedem Endanwender eine eigene Library-Base zuweist. Dementsprechend braucht man nicht Hand an die Funktionen selber zu legen, sondern nur die Sprungtabelle inklusive des Library-Records für jede Instanz zu reproduzieren (kopieren). Ist allerdings nicht der sauberste Stil, weil eine Shared-Bibliothek im Grunde genommen reentrant sein sollte und nicht nur thread-safe. Als Ergänzung zu whose Worten kann ich Dir nur ans Herz legen, Weaver (amimedic.de) herunter zu laden. Es ist ein Programm, das Dir anhand von SFD-Dateien die Grundgerüste für Shared-Libraries erzeugt, und zwar für OS3/AROS/MorphOS und OS4. Alles was Du dazu brauchst ist dann ein Texteditor, einen C-Compiler, Weaver und fd2pragma und Du erstellst für alle vier Plattformen die benötigten Dateien, inklusiver derer für die Endbenutzer. Nach wie vor musst Du aber erst einmal Deine Funktionen so schreiben, dass diese auch mindestens thread-safe sind, besser wäre aber reentrant. Kriegst Du das nicht hin, klone wie oben beschrieben die Library-Base für jedes aufrufende Programm und dann sollte auch einer Amiga-Implementierung nichts im Wege stehen. Willst Du weiterhin C++ benutzen, bleibt Dir sowieso nichts anderes übrig, es sei denn, Du kannst exakt bestimmen, ob der vom C++-Compiler generierte Code thread-safe ist. Mein Fazit: Wenn man denkt es geht nicht mehr, kommt von irgendwo ein Lichtlein her. Oder anders gesagt, ich hoffe, dass Du jetzt nicht mehr ganz so schwarz siehst. Grüße [ - Answer - Quote - Direct link - ] |
2010-05-02, 13:47 h Der_Wanderer Posts: 1229 User |
Danke für die vielen Hinweise. Alles hat natürlich seine Gründe. Was bleibt ist aber, Windows DLL luppt, AmigaOS luppt nicht. Die C Runtime zu benutzen sollte ja gerade dahin führen, dass der Code portabel ist. Ist mir schon klar dass ich es machen könnte direkt mit AmigaOS, nur ist das eine Zeit frage, wieviel man in die AmigaOS version stecken kann. Eine Shared library will ich aus verschiedenen Gründen machen. 1. Ich will dass es unter allen Sprachen nutzbar ist, auch Amiblitz. 2. Es geht um Sprachsynthese, wo es gemeinsame Resourcen gibt, z.B. die Lexica und die Stimmen. Wenn ich da ein Update mache, ist das sehr schnell nicht mehr kompatibel. Wenn es eine statische Lib ist, wären die Nutzer der Sprachsynthese zu einem update gezwungen. Stell euch vor, bei einem AHI update müssten alle Programme re-compiliert werden, die AHI benutzen, oder sie würden nicht mehr funktionieren. Das wäre No-Go. -- HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ - Answer - Quote - Direct link - ] |
2010-05-02, 14:13 h ZeroG Posts: 1487 User |
@Der_Wanderer:Zitat:Also wenn du #ifdefs sparen möchtest sowie auf Windows/Linux DLLs und auf AmigaSystemen Libraries benutzen möchtest, dann mach doch kleine Wrapper-Funktionen die die oben genannten Funktionen vom rest des Programms abkapseln. Dann hättest du je eine Systemexklusive Quelltextdatei die du bequem und übersichtlich im makefile abfrühstücken kannst. Der aufwand hält sich in grenzen und zusätzlich kannst du leicht für jede Amigageschmacksrichtung spezielle änderungen vornehmen - falls nötig. [ - Answer - Quote - Direct link - ] |
2010-05-02, 17:44 h whose Posts: 2156 User |
Zitat: Ja, aber es luppt auch nur deswegen als DLL, weil man bei Winzigweich entsprechend Aufwand mit dem OS getrieben hat. Normalerweise würde das genauso wenig luppen. Zitat: Wie von meinem Vorredner schon aufgezeigt, sooo doll ist der Aufwand eigentlich nicht. Davon ab, Nutzung der C-Runtime bedeutet nur "portabel bei ausschließlicher Nutzung der Möglichkeiten der Runtime/Standard-Link-Library". Streng genommen ist nicht einmal der Weg DLL/.so im Sinne des C-Standards "portabel". Kannst ja mal bei Hyperion anfragen, ob sie Dir den DLL-Lader von Heretic 2 zur Verfügung stellen. Machbar ist sowas auch für AmigaOS 68k, es fragt sich nur, ob jemand anders den Aufwand für Dich betreiben möchte, wenn Du selbst gewissen Aufwand trotz hoher Ansprüche scheust. Zitat: Die Pro/Contra-Argumente sind doch lange bekannt. Fakt ist aber, "mal eben" Code, der die C-Standardfunktionen nutzt, in eine Amiga-shared-Library packen ist nicht drin. Aufwand wirst Du so oder so haben, wann immer Du Code fabrizierst, der vom Standardvorgehen bei der Programmierung in C abweicht (geteilter Code ist so ein Abweichung). Ok, manchmal übernehmen die Entwickler des Betriebssystems den Aufwand für Dich und basteln, naja, interessante, Lösungen dazu, aber für AOS 68k fällt das auf alle Fälle flach, da passiert in dieser Richtung wohl eher nichts mehr. Da mußt Du Dir dann die Frage stellen, ob Du den Aufwand (der bei gut durchdachtem Aufbau wirklich nicht gewaltig ist) treiben willst oder eben nicht. Hier kann Dir diese Entscheidung niemand abnehmen, nur Wege aufzeigen, wie Du Dein Ziel eben doch erreichen kannst. Allerdings niemals ohne zusätzlichen Aufwand im Gegensatz zur Windows-DLL-Variante. -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Answer - Quote - Direct link - ] |
2010-05-02, 22:46 h jolo Posts: 110 User |
@Der_Wanderer:Zitat: Benötigst Du dazu die mathematischen Bibliotheken? - sprich Fließkommazahlen? Dann rennst Du nämlich ins nächste Problem. Schon Anweisungen wie: z = i + 1.5; oder i = z / 2.0; benutzten auf dem Amiga Compiler-spezifische Routinen, die ausschließlich in der jeweiligen C-Runtime Bibliothek zu finden sind. Erschwerend kommt hinzu, aber eher von theoretischer Natur, wenn ich das noch recht in Erinnerung habe, dass man jedwede zu benutzende mathematische Bibliothek von dem Prozess, der sie verwendet, auch öffnen lassen muss, und nicht nur einmal, wie sonst üblich. Der Grund liegt darin begründet, dass eine Ressource (ausschließlich ein Benutzer für die Nutzungsdauer gestattet) anstelle einer Software bzw. einer Software-Hardware-Lösung verwendet werden könnte und diese per Definition ausschließlich von dem Prozess, der sie öffnete, auch geschlossen werden darf. @whose: "Winzigweich"? Habe den Ausdruck noch nicht vernommen. Zitat: Ja, da hast Du Recht. Allerdings kommt so etwas als zentrale Schnittstelle für ein schlankes, halbwegs effizientes Betriebssystem nicht infrage, weil: a) zur Laufzeit externe Verweise aufgelöst werden müssen b) zur Laufzeit die Sprungadressen ermittelt werden müssen c) die Sprungadressen anhand des Namens ermittelt werden d) ein zentraler Prozess die Nutzung dieser dynamischen Bibliotheken gewährleisten muss In Zeiten von C#/Java und zig Giga-Hertz spielt das für Endanwender aber keine Rolle mehr, weil man es nicht wahrnimmt, bzw. die Geschwindigkeit als ausreichend erachtet. Das gleiche für OS3, selbst mit einer 100 MHz 68060 CPU, würde abschreckend wirken. Ich gebe zu, dass eine Amiga-Shared Bibliothek um ein vielfaches schwieriger zu erstellen ist als eine '.dll', jedoch ist ihre Verwaltung aus Sicht einer CPU effektiver. Zudem hat Microsoft den Sprach-Standard von C um "__declspec" erweitert, damit es dem Programmierer leichter gemacht wird, eine '.dll' zu erstellen. So was müsste es für AmigaOS/AROS/MorphOS geben... Zitat: Ganz genau. Das Problem, dass der Der_Wanderer haben dürfte, sind nicht MorphOS und AmigaOS4, sondern ausschließlich das AmigaOS3. Unter MorphOS die richtige 'specs'-Datei für "gcc" installieren, gegen "libnix" linken und fertig. Unter AmigaOS4 ein Shared-Object erstellen, wahlweise mit "gcc" oder "vbcc", fertig. Nur unter AmigaOS3 sind die Probleme mannigfaltig. Bezüglich AROS kann ich leider nichts Aussagefähiges beisteuern, weil ich einen m68k gehosteten "gcc" mit i386-AROS Backend verwende, also ein Unikum. @Der_Wanderer: Würdest Du nur eine Plattform unterstützen wollen, wäre es sehr viel einfacher. Alle vier zu unterstützen, ist möglich aber mit Aufwand verbunden. Grüße [ - Answer - Quote - Direct link - ] |
2010-05-03, 12:12 h Der_Wanderer Posts: 1229 User |
Ich wusste schon dass floats Probleme machen können, deshalb habe ich fast alles mittels Integern implementiert, zumindest in den Schnittstellen. Intern verwende ich hier und da Floats, z.b. um ein Hamming Fenster zu berechnen etc. Verstehe ich aber nicht ganz, in Amiblitz kann ich doch auch Floats in Shared Libs benutzen. Meine Situation sieht momentan so aus: 1. Die TTS (Sprachsynthese) Engine ist in Amiblitz3 implementiert und funktioniert auch gut. 2. Ich möchte die Engine unter Windows/Linux/MacOS/iPhone/Android/... nutzen, das hat die höchste Priorität für mich, nicht die Amiga Version (man muss ja von irgendwas leben...). Auf dem Amiga habe ich das nur entwickelt weil es viel schneller geht in Amiblitz als in C, und ich dort die nötigen Bibliotheken bereits hatte. Für die non-Amiga Plattformen (und auch AROS) bräuchte ich das ganze nun in C, weil es der kleinste gemeinsame Nenner ist. Wäre aber schade, wenn ich diesen C Code nicht unter AmigaOS wieder verwenden könnte. Wäre ja schon grotesk, unter AmigaOS entwickelt aber dort als einzige Plattform nicht veröffentlicht... Mein Plan bisher: Alles nach plain-C portieren. Unter Windows eine DLL, under Linux eine .so, unter Amiga eine Shared Library. Evtl. gibt aber auch bessere Lösungen? -- HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ - Answer - Quote - Direct link - ] |
2010-05-03, 12:45 h Thore Posts: 2266 User |
> Evtl. gibt aber auch bessere Lösungen? Wenn sich an Deiner API nichts oder nichts relevantes ändert, sind Libs eine gute Wahl, denn so müsstest Du bei Updates nur die Lib tauschen, und nicht alle Programme, die die Funktionen haben. [ - Answer - Quote - Direct link - ] |
2010-05-03, 12:55 h whose Posts: 2156 User |
@Der_Wanderer: Ehrlich gesagt, mir fällt keine bessere ein, als die Standardfunktionen in Wrapper zu verpacken (und für AOS im Wrapper OS-Funktionen statt C-Standard zu verwenden), um eine gewisse Unabhängigkeit vom startup code zu erreichen. Sowas ließe sich auch noch recht simpel im makefile abfrühstücken, ohne #ifdef-Orgie. Mir ist auch nicht ganz klar, weswegen Du z.B. printf() verwenden willst. Für GUI-Programme wäre das selbst unter Win ein No-Go, es sei denn, Du baust auch dafür wieder Wrapper bzw. nutzt systemabhängige Lösungen. Der ganze fxxxx()-Krempel gehört eigentlich auch nicht in eine systemabhängige dynamische Bibliothek, Gründe dafür wurden hier schon öfter genannt. Ok, irgendwie muß Deine Lib ja die Daten laden, ist schon klar, aber, wie schon erwähnt, sowas ist im Grunde nicht mehr "portabel". Eventuell solltest Du Dein Design nochmal etwas überdenken. Gut, der Weg via .dll/.so & Standardfunktionen ist trivial, aber nicht wirklich schön, und irgendwann beißt es Dich in den Hintern. Oder, wie im Fall von AmigaOS 3.x, gleich von vornherein. -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Answer - Quote - Direct link - ] |
2010-05-03, 22:23 h jolo Posts: 110 User |
@Der_Wanderer:Zitat: Du kannst sie auch innerhalb einer in C erstellten Bibliothek verwenden, leider aber nicht die Versionen, die in der statischen Compiler (Runtime) Biblitohek zu finden sind, denn, wir näheren uns wieder dem Anfang dieses Threads, unter OS3 sind diese nicht thread-safe und zum Anderen setzen sie Teile des Startup-Codes als gegeben voraus. Ich bin ein wenig überfragt, wie Amibltiz Fließkommazahlen handhabt und ob mittels Amiblitz erstellte Funktionsbibliotheken wirklich reentrant sind. Unter C jedoch gibt es diverse Referenzen zu Funktionen, die zwar alle dasselbe tun, z.B. dividieren, aber unterschiedliche Bezeichner haben, weil es neben FLOAT und DOUBLE noch die internen Formate der 68881/68882/68040/68060 FPUs gibt, die auch unterstützt werden. Diese Funktionsnamen sind in den betreffenden Compilern fest verankert, z.B. __muldf3(), __fixsfsi(), __floatsisf(), __divsf3(), um nur einige unter "gcc" zu nennen. Und diese müssen zwingend reentrant für eine Amiga Shared-Library sein, ansonsten musst Du nämlich jede Funktion, die eine dieser Routinen benutzt, solange sperren, bis die betreffende Routine wieder frei zur Verfügung steht. Wohl kaum durchführbar. So, nachdem ich mir jetzt mal kurz das 'Change.log' zu "clib2" angeschaut habe, gehe ich davon aus, dass alle Funktionen die Du benötigst, darin enthalten sind, auch die Compiler-spezifischen für FLOAT und DOUBLE. Damit kannst Du schon mal OS3 und OS4 abdecken. Unter MorphOS ist "libnix" das Äquivalent. Macht schon mal drei von vier. Ich hoffe, dass unter AROS die zur Verfügung stehenden "Static Libs" thread-safe sind, dann hättest Du nämlich alle vier abgedeckt. Grüße [ - Answer - Quote - Direct link - ] |
2010-05-04, 14:20 h Holger Posts: 8116 User |
Zitat:Real-life Code und portabler Code im Sinne von C scheinen sich ohnehin von vornherein auszuschließen. Zitat:Für shared libraries ist es sowieso ein No-Go, denn die Bibliothek weiß ja gar nicht, ob das aufrufende Programm ein GUI-Programm ist, bzw. ob es überhaupt eine Konsole besitzt, bzw. was es bedeutet, in die jeweilige Standardausgabe zu schreiben. Hinter dieser kann sich schließlich auch etwas ganz anderes als eine Konsole verbergen. Zitat:Das ist der Hersteller von äußerst bekannter Software namens "Fenster" und "Büro", wobei aber nicht, wie man meinen könnte, das Büro ein oder mehrere Fenster besitzt, sondern "Büro" innerhalb von "Fenster" installiert wird... Zitat:Ähem. So etwas passiert genau einmal nach dem Laden der Bibliothek, und ähnliches passiert auch beim Amiga, wenn nach dem Laden einer ausführbare Datei Adressen an die tatsächliche Position im Speicher angepasst werden. Zitat:Deshalb funktionieren DLLs selbst unter Windows 3.1 auf einem 386 mit 14MHz... Zitat:Wenn man bedenkt, dass der identische Library-Initialisierungscode, inkl. der Verwaltung des Zählers für Anzahl benutzender Programme sich in jeder Bibliothek erneut wiederfinden, statt einmal im Betriebssystem, relativiert sich diese Effizienz erheblich. Die Design-Entscheidung, keine symbolischen Namen, sondern eine Tabelle mit 68k-Sprungbefehlen relativ zum Register A6 zu benutzen, die selbst unter der bevorzugten Programmiersprache C ein Fremdkörper ist, muss man akzeptieren. Aber nicht unbedingt glorifizieren. Diese Art des Linkens ist aber auch gar nicht der Grund, warum man Amiga-Libraries nicht so wie Windows oder Unix-Libraries benutzen kann. Der springende Punkt ist hier, dass man nicht die Datensegmente einer Objektdatei automatisch pro Prozess anlegen lassen kann. -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2010-05-04, 15:09 h Der_Wanderer Posts: 1229 User |
Eine GUI Applikation unter Windows kann auch ausgaben mittels printf machen. Man sieht sie nur nicht, weil keine Console aufgeht. Aber man kann sie in eine File pipen. Also als No-Go würde ich das nicht bezeichnen. Das Argument mit der Effizienz kann ich auch nicht gelten lassen. Wie Holger gesagt hat, die Klartext Funktionen müssen nur einmal beim Programm start in Jump Offsets aufgelöst werden. Das ist selbst auf einem A500 ein vertretbarer und kaum spürbarer Aufwand. Wenn ich das richtig sehe ist der große Unterschied, dass DLLs jedesmal beim öffnen ihren eigenen Kontext erzeugen, während Amiga Shared Libraries nur einmal gestartet werden, und dann von mehreren Prozessen verwendet werden können. Das bringt natürlich einige Probleme mit sich, z.B. man kann bei printf nicht sofort sagen, was der richtige File Handle für den Output wäre. Wenn man die vor und Nachteile abwiegt, ist die Amiga Shared Library etwas leichtgewichtiger als die DLL, aber viel schwerer vom Entwickler korrekt zu implementieren. Und eine Library, die 2ms länger braucht zum starten ist besser als keine Library. Dafür würde man sich heute wohl kaum mehr entscheiden. Zu Amiblitz: Floats werden entweder direkt inline per Softfloat berechnet oder per FPU Instruction. Da findet kein Funktionsaufruf oder ähnliches statt. Bei einer Shared Library wird der Basic Kontext beim init Code der Library erzeugt. So hat jede Library ihren eigenen Basic Context, nicht aber jeder Nutzer einer Library. Ob eine Funktion re-entrant ist oder nicht, hängt wie in jeder anderen Sprache davon ab was man da drin so tut. Wenn man gemeinsame Resourcen nutzt, muss man den Funktionsaufruf per Semaphore thread safe machen. Dafür gibt es Macros (lib_Lock und lib_Unlock). Ob das ok ist oder nicht hängt ganz von der Funktion/Aufgabe ab. Consolen Output ist möglich, wenn man sich den File Handle der Console bei jedem Aufruf vom aufrufenden Thread besorgt. Global darf man den natürlich nicht speichern. -- HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, AB3 Includes und viele mehr... Homepage: http://www.hd-rec.de [ Dieser Beitrag wurde von Der_Wanderer am 04.05.2010 um 15:11 Uhr geändert. ] [ - Answer - Quote - Direct link - ] |
-1- 2 3 4 5 | [ - Post reply - ] |
amiga-news.de Forum > Programmierung > C oder C++? | [ - Search - New posts - Register - Login - ] |
Masthead |
Privacy policy |
Netiquette |
Advertising |
Contact
Copyright © 1998-2024 by amiga-news.de - all rights reserved. |