amiga-news DEUTSCHE VERSION
.
Links| Forums| Comments| Report news
.
Chat| Polls| Newsticker| Archive
.

amiga-news.de Forum > Programmierung > Gleiches Programm wird von GCC kompiliert aber nicht von G++ ? [ - Search - New posts - Register - Login - ]

-1- 2 3 [ - Post reply - ]

2005-08-09, 13:36 h

Amaris
Posts: 941
User
Hallo

Ich habe neulich ein Programm aus diesem C-Kurs hier ausprobiert

http://www.liquido2.com/tutorial/deutsch/


http://www.amaris.de.vu/main.c


Es soll eigentlich nur ein Fenster auf die Workbench bringen. Lässt sich auch problemlos mit GCC kompilieren und funktioniert.
Nun wollte ich auf eigene Faust ein paar Änderungen vornehmen, allerdings in C++. Ich habe also <iostream> eingebunden und wollte das Ganze mit g++ kompilieren. Ich bekam eine Fehlermeldung.
Daraufhin habe ich meine eigenen Änderungen in C++ wieder rückgängig gemacht und nur das originale Programm mit g++ kompiliert. Wieder bekam ich die gleiche Fehlermeldung, nämlich:

code:
g++  -c -o o/gcc-classic-stable/main.o main.c
main.c: In function 'int main()':
main.c:53: assignment to 'UBYTE *' from 'const char *' discards qualifiers
make: *** [o/gcc-classic-stable/main.o] Error 1
Done.


In Zeile 53 steht:

MyText.IText = "Servus !";

Leider verstehe ich nicht was hier genau der Fehler ist.

MfG
Amaris





--
-Amiga 1200, 68030 @ 50 Mhz, 4 GB HDD, 16 MB RAM, externes PCMCIA-CD-ROM-Laufwerk

[ - Answer - Quote - Direct link - ]

2005-08-09, 14:55 h

DariusBrewka
Posts: 899
[Banned user]
Mit C++ habe ich zwar schon langen nichts mehr gemacht aber wie es ausschaut bemängelt er, dass du MyText.IText einen Zeiger auf einen konstanten Text (ein Text welcher sich nicht ädert) übergibst. Versuche einfach mal MyText.IText = (UBYTE*) "Servus!";.

Ich denke mal g++ geht Strenger mit den Datentypen um und erwartet dass man sich an die Typen 100% hält.

[ - Answer - Quote - Direct link - ]

2005-08-09, 15:42 h

Solar
Posts: 3680
User
Korrekte Vermutung. C++ ist strikter in der Typprüfung - es stößt sich zum einen daran, das nach der Zuweisung das "const" verschwunden ist, zum zweiten das hier eine inkompatible Zuweisung erfolgt.

Mit einem expliziten Cast ist das zu beheben; statt des oben vorgeschlagenen C-Cast (TYPENAME)var ist aber ein dynamic_cast<TYPENAME>, static_cast<TYPENAME> oder reinterpret_cast<TYPENAME> vorzuziehen - expliziter, per Volltextsuche leichter zu finden, und eher dem Typkonzept von C++ entsprechend. Details im C++-Handbuch Deines Vertrauens. ;)

[ - Answer - Quote - Direct link - ]

2005-08-09, 23:10 h

Holger
Posts: 8116
User
Allerdings glaube ich nicht, daß C++ Programmierung mit den original Amiga-Headern/Strukturen Spaß machen wird. Die IText-struct liefert nur einen kleinen Vorgeschmack darauf, was so alles an inkonsistenten Datentypen kommen wird.
Selbst unter C ist ein typischer Amiga-Source voll von type-casts, die bei sinnvolleren Definitionen der Strukturen überflüssig wären.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2005-08-10, 00:56 h

whose
Posts: 2156
User
Zitat:
Original von Holger:
Allerdings glaube ich nicht, daß C++ Programmierung mit den original Amiga-Headern/Strukturen Spaß machen wird. Die IText-struct liefert nur einen kleinen Vorgeschmack darauf, was so alles an inkonsistenten Datentypen kommen wird.
Selbst unter C ist ein typischer Amiga-Source voll von type-casts, die bei sinnvolleren Definitionen der Strukturen überflüssig wären.


Hm, die meisten Typecasts gehen auf Zeiger zurück. Wie will man denn Casts vermeiden, wenn viel mit Zeigern auf unterschiedliche Strukturen gearbeitet wird? Abgesehen davon bietet sich dadurch doch erst die Möglichkeit, den Compiler einen Großteil der Typüberprüfung erledigen zu lassen... (?)

Naja, was heute sinnvoll erscheint war damals (1984) halt noch kein Thema (und C++ war auch noch keins zu dieser Zeit :D ). Insofern sind die Definitionen den Strukturen schon recht sinnvoll, manches davon war auch einfach nur als Arbeitserleichterung gedacht, wie z.B. die Taglisten. Zu der Zeit, als man auf diese (zugegebenermaßen "glorreiche" I-) ) Idee kam, hat noch niemand daran gedacht, Funktionseinsprünge per Makro erledigen zu lassen anstatt über eine Linkerbibliothek mit Stub-Funktionen. Daher auch die Probleme damit, wenn C++-Compiler da dran müssen.

Andererseits ist man unter AmigaOS eher selten gezwungen, solche Sachen zu benutzen oder in der VarArg-Form an die jeweilige Funktion zu übergeben. Es gibt schließlich immer noch die Stubs.

Die IText-Struktur ist zwar ein anderes Thema, aber ich frage mich gerade, was daran _nicht_ sinnvoll ist, ein UBYTE * als Typ zu verwenden? Normalerweise kommen Stringkonstanten da eher selten zur Anwendung, wenn ich mich nicht sehr täusche.

Und es wäre etwas dumm, wenn man das als const char * bzw. CONST UBYTE definiert hätte, dann würde ein C++-Compiler wohl noch viel öfter meckern bzw. Nicht-konstante Strings (wie sie doch ziemlich häufig vorkommen) würden halsbrecherische Casts erzwingen...

Oder sehe ich das falsch, als C++-Nichtkenner? I-)

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Answer - Quote - Direct link - ]

2005-08-10, 01:39 h

Holger
Posts: 8116
User
Zitat:
Original von whose:
Hm, die meisten Typecasts gehen auf Zeiger zurück. Wie will man denn Casts vermeiden, wenn viel mit Zeigern auf unterschiedliche Strukturen gearbeitet wird? Abgesehen davon bietet sich dadurch doch erst die Möglichkeit, den Compiler einen Großteil der Typüberprüfung erledigen zu lassen... (?)

Eben. Wenn ich einen typecast einfügen muß, weil ein Entwickler bei Commodore aus Faulheit den return-type einer OS-Funktion als APTR deklariert hat, obwohl die Funktion einen sehr wohl definierten Typen zurückliefert, den man zumeist spätestens beim Zurückgeben der Resource auch mit dem exaktem Typen übergeben muß, was habe ich dann noch von der Typsicherheit des Compilers?
Zitat:
Insofern sind die Definitionen den Strukturen schon recht sinnvoll, manches davon war auch einfach nur als Arbeitserleichterung gedacht, wie z.B. die Taglisten.
Die TagList sind im Gegensatz zum Rest überhaupt kein Problem. Das sind ja ausnahmesweise sogar mal Strukturen, die keine Abhängigkeiten zu Internas des OS enthalten.
Zitat:
Die IText-Struktur ist zwar ein anderes Thema, aber ich frage mich gerade, was daran _nicht_ sinnvoll ist, ein UBYTE * als Typ zu verwenden? Normalerweise kommen Stringkonstanten da eher selten zur Anwendung, wenn ich mich nicht sehr täusche.
Eigentlich kommen fast nur Konstanten zur Anwendung, wenn überhaupt noch jemand diese alte Struktur verwendet.
Zitat:
Und es wäre etwas dumm, wenn man das als const char * bzw. CONST UBYTE definiert hätte, dann würde ein C++-Compiler wohl noch viel öfter meckern bzw. Nicht-konstante Strings (wie sie doch ziemlich häufig vorkommen) würden halsbrecherische Casts erzwingen...

Oder sehe ich das falsch, als C++-Nichtkenner? I-)

Scheint so.
Wenn ich eine OS-Routine aufrufe, die per const-Deklaration garantiert, daß sie meinen string nicht verändert, kann ich selbstverständlich auch nicht-Konstante strings übergeben.
Die OS-Routine darf sie natürlich trotzdem nicht verändern.
Und die IText-Struktur ist genau dafür da, an eine Routine zum Rendern übergeben zu werden.
Glaub mir, richtig angewendet brächte man nie die const-Eigenschaft per cast zu verändern, oder fats nie.

Übrigens gibt es noch mehr als nur falsche Zeigertypen und fehlende const-Deklarationen in den AmigaOS-includes. Es gibt z.B. auch noch falsche signed und unsigned, die für viel Spaß sorgen.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2005-08-10, 02:40 h

whose
Posts: 2156
User
Zitat:
Original von Holger:
Eben. Wenn ich einen typecast einfügen muß, weil ein Entwickler bei Commodore aus Faulheit den return-type einer OS-Funktion als APTR deklariert hat, obwohl die Funktion einen sehr wohl definierten Typen zurückliefert, den man zumeist spätestens beim Zurückgeben der Resource auch mit dem exaktem Typen übergeben muß, was habe ich dann noch von der Typsicherheit des Compilers?


Öhm... welche der zahlreichen Funktionen ist denn so "nachlässig" definiert? Außer, sie gibt einen Zeiger auf einen generisch genutzten Speicherbereich zurück, wie z.B. AllocMem(). Was sollte man da als Rückgabewert definieren? const unsigned char *? :D Oder doch besser void * sprich APTR? I-)

Zitat:
Zitat:
Insofern sind die Definitionen den Strukturen schon recht sinnvoll, manches davon war auch einfach nur als Arbeitserleichterung gedacht, wie z.B. die Taglisten.
Die TagList sind im Gegensatz zum Rest überhaupt kein Problem. Das sind ja ausnahmesweise sogar mal Strukturen, die keine Abhängigkeiten zu Internas des OS enthalten.

Dafür reichlich Abhängigkeit zur Maschine. Schließlich sind die Funktionen, die Taglisten verwursten, mit "struct TagItem *" als Parameter definiert. Die Funktionen, die die Taglisten als VarArg-Parameter akzeptieren (und genau dafür sind die Taglisten gedacht!), bauen darauf, daß man Zeiger- und ULONG-Typ innerhalb der TagItem-Struktur beliebig casten kann. Ansonsten wären z.B. die inline-Aufrufe der VarArg-Varianten gar nicht machbar. Der GCC meckert trotzdem gerne bei solchen Funktionen, wie z.B. BestModeID(). Da kommt dann sowas wie "...pointer to function makes pointer from integer without a cast"... also doch nicht ganz glücklich gelöst.

Zitat:
Zitat:
Die IText-Struktur ist zwar ein anderes Thema, aber ich frage mich gerade, was daran _nicht_ sinnvoll ist, ein UBYTE * als Typ zu verwenden? Normalerweise kommen Stringkonstanten da eher selten zur Anwendung, wenn ich mich nicht sehr täusche.
Eigentlich kommen fast nur Konstanten zur Anwendung, wenn überhaupt noch jemand diese alte Struktur verwendet.

Sei mir bitte nicht böse, aber Konstanten verwende ich z.B. eher selten im Zusammenhang mit IText. Da kommen höchstens Texte hinein, die mir die locale.library liefert, und diese Strings sind nur scheinbar konstant...

Zitat:
Zitat:
Und es wäre etwas dumm, wenn man das als const char * bzw. CONST UBYTE definiert hätte, dann würde ein C++-Compiler wohl noch viel öfter meckern bzw. Nicht-konstante Strings (wie sie doch ziemlich häufig vorkommen) würden halsbrecherische Casts erzwingen...

Oder sehe ich das falsch, als C++-Nichtkenner? I-)

Scheint so.
Wenn ich eine OS-Routine aufrufe, die per const-Deklaration garantiert, daß sie meinen string nicht verändert, kann ich selbstverständlich auch nicht-Konstante strings übergeben.


Das Dumme ist nur, daß die entsprechende Funktion genau das _nicht_ tut. Sie erwartet als Parameter einen Zeiger auf die IText-Struktur, nicht auf den darin enthaltenen String... von einer Garantie der Unversehrtheit mal ganz zu schweigen. Aber den Text verändert sie ja tatsächlich nicht. Weiteres siehe unten.

Zitat:
Die OS-Routine darf sie natürlich trotzdem nicht verändern.
Und die IText-Struktur ist genau dafür da, an eine Routine zum Rendern übergeben zu werden.
Glaub mir, richtig angewendet brächte man nie die const-Eigenschaft per cast zu verändern, oder fats nie.


Streng genommen bräuchte man den jeweiligen String nie konstant zu definieren. Läßt man das nämlich und legt den String dynamisch an (was auch sauberer wäre, meines Erachtens nach), kann man sich den Cast sparen. Oder erbt ein Zeiger auf ein char-Array (bzw. UBYTE *) die const-Eigenschaft einer String-Konstanten in C++?

Nichts anderes landet nämlich in der IText-Struktur (ein UBYTE *), und die ist darauf ausgelegt, beliebig und jederzeit wiederverwendet zu werden. Das wäre ein wenig schwierig mit einer String-Konstanten. Dann müßte man mehrere Strukturen für jeden neuen Text jedesmal gleich zu Beginn definieren, oder nicht? Das kann, je nach Programm, ganz schön aufwändig werden... I-)

Zitat:
Übrigens gibt es noch mehr als nur falsche Zeigertypen und fehlende const-Deklarationen in den AmigaOS-includes. Es gibt z.B. auch noch falsche signed und unsigned, die für viel Spaß sorgen.

Das ist allerdings richtig. Die signed/unsigned-Geschichten bei manchen Parametern habe ich auch schon öfter verflucht (bzw. das fest eingebaute "-traditional" des StormC-GCC). Sieht man das aber geschichtlich, wird deren Anwendung wieder verständlich. Effizienz in Sachen Speicherverbrauch. Das Zeugs hatte und hat schon seinen Sinn...

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233


[ Dieser Beitrag wurde von whose am 10.08.2005 um 02:58 Uhr editiert. ]

[ - Answer - Quote - Direct link - ]

2005-08-10, 02:51 h

whose
Posts: 2156
User
Nachtrag:

Die Inkonsistenzen bei OpenLibrary() und CloseLibrary() haben wir eigentlich nur der dos.library zu verdanken. Die tanzte als erste aus der Reihe, was den Struktur-Typ betrifft (bzw. die notwendige Erweiterung der Library-Struktur).

Die anderen Fälle (mir fällt jetzt gerade nichts konkretes ein, aber da gabs noch ein paar, soweit ich mich erinnere) gehen auf Unstimmigkeiten bei der Nomenklatur zurück und tauchen dementsprechend auch nur in den Includes auf. Die Typen bei OpenLibrary() und CloseLibrary() sind aber korrekt.

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Answer - Quote - Direct link - ]

2005-08-10, 09:08 h

gni
Posts: 1106
User
Zitat:
whose:
Wie will man denn Casts vermeiden, wenn viel mit Zeigern auf unterschiedliche Strukturen gearbeitet wird? Abgesehen davon bietet sich dadurch doch erst die Möglichkeit, den Compiler einen Großteil der Typüberprüfung erledigen zu lassen... (?)

Irrtum. Durch Casts nimmst Du dem Compiler die Möglichkeit zur Typprüfung. Mit Casts sagst Du ja explizit, das Du es besser weisst.
Zitat:
Naja, was heute sinnvoll erscheint war damals (1984) halt noch kein Thema (und C++ war auch noch keins zu dieser Zeit :D ). Insofern sind die Definitionen den Strukturen schon recht sinnvoll
Nö, sind sie nicht. Die Verwendung von UBYTE ist ein Problem, genau wie STRPTR.
Zitat:
Zu der Zeit, als man auf diese (zugegebenermaßen "glorreiche" I-) ) Idee kam, hat noch niemand daran gedacht, Funktionseinsprünge per Makro erledigen zu lassen anstatt über eine Linkerbibliothek mit Stub-Funktionen. Daher auch die Probleme damit, wenn C++-Compiler da dran müssen.
Funktionsaufrufe per Makro? Das ging damals eh nicht, da Du die Parameter immernoch in Registern übergeben mußt und das konnte damals kein Compiler.
Zitat:
Und es wäre etwas dumm, wenn man das als const char * bzw. CONST UBYTE definiert hätte, dann würde ein C++-Compiler wohl noch viel öfter meckern bzw. Nicht-konstante Strings (wie sie doch ziemlich häufig vorkommen) würden halsbrecherische Casts erzwingen...
Unsinn, das ist kein Problem. Umgekehrt wird ein Schuh draus.

[ - Answer - Quote - Direct link - ]

2005-08-10, 09:12 h

gni
Posts: 1106
User
Zitat:
Holger:
Die TagList sind im Gegensatz zum Rest überhaupt kein Problem. Das sind ja ausnahmesweise sogar mal Strukturen, die keine Abhängigkeiten zu Internas des OS enthalten.

Probleme haben sie trotzdem, wegen Zeiger/Nichtzeiger in ti_Data. AFAICT wurden TagListen zuerst bei Motif verwendet.

[ - Answer - Quote - Direct link - ]

2005-08-10, 09:27 h

gni
Posts: 1106
User
Zitat:
whose:
Die Funktionen, die die Taglisten als VarArg-Parameter akzeptieren (und genau dafür sind die Taglisten gedacht!), bauen darauf, daß man Zeiger- und ULONG-Typ innerhalb der TagItem-Struktur beliebig casten kann.

Die VarArgs-Varianten sind nur _Hilfsfunktionen_ ("convenience")!
Zitat:
Ansonsten wären z.B. die inline-Aufrufe der VarArg-Varianten gar nicht machbar.
Die normale Funktion mit TagList* als Argument aber auch nicht. Beim Füllen der TagList mußt Du _auch_ Casten.
Zitat:
Der GCC meckert trotzdem gerne bei solchen Funktionen, wie z.B. BestModeID(). Da kommt dann sowas wie "...pointer to function makes pointer from integer without a cast"... also doch nicht ganz glücklich gelöst.
Das ist _ausschließlich_ ein Problem "Implementation". Der GCC unterstützt Makros mit variablen Argumenten und dieses Feature wird von den Inlines verwendet. Die Argumente werden in ein ULONG-Array gepackt. Und genau das ist die Stelle, an der die Warnung kommen _muß_. Die beschriebene Methode ist äußerst ineffizient. Deshalb empfehle ich generell mit NO_INLINE_STDARG zu arbeiten. Zum einem gibt es dann keine Warnung und außerdem ist der generierte Code dann um Längen besser.
Zitat:
Sei mir bitte nicht böse, aber Konstanten verwende ich z.B. eher selten im Zusammenhang mit IText. Da kommen höchstens Texte hinein, die mir die locale.library liefert, und diese Strings sind nur scheinbar konstant...
Irrelevant. Der Texteintrag in IText kann trotzdem ein "const" haben und Du kannst dennoch Deinen const-losen Typ zuweisen.
Zitat:
Streng genommen bräuchte man den jeweiligen String nie konstant zu definieren.
Weisst Du eigentlich wie const funktioniert und was es aussagt? :-(

[ - Answer - Quote - Direct link - ]

2005-08-10, 11:39 h

whose
Posts: 2156
User
Zitat:
Original von gni:
Zitat:
whose:
Die Funktionen, die die Taglisten als VarArg-Parameter akzeptieren (und genau dafür sind die Taglisten gedacht!), bauen darauf, daß man Zeiger- und ULONG-Typ innerhalb der TagItem-Struktur beliebig casten kann.

Die VarArgs-Varianten sind nur _Hilfsfunktionen_ ("convenience")!

Genau. Und davon schrieb ich einen Post vorher. Das vieles, was einem heute in den Includes merkwürdig vorkommen mag, damals dazu gedacht war, den externen Entwicklern das Leben zu erleichtern.

Zitat:
Zitat:
Ansonsten wären z.B. die inline-Aufrufe der VarArg-Varianten gar nicht machbar.
Die normale Funktion mit TagList* als Argument aber auch nicht. Beim Füllen der TagList mußt Du _auch_ Casten.

Eben. Deswegen sagte ich ja auch, daß das keine besonders glückliche Lösung war mit den Taglisten. Die Inlines/Stubs bauen noch dazu auf einer Eigenschaft auf, die nicht auf jeder Maschine garantiert sein muß. Wenn dieser Fall eintritt hilft auch kein Cast mehr...;(

Zitat:
Zitat:
Der GCC meckert trotzdem gerne bei solchen Funktionen, wie z.B. BestModeID(). Da kommt dann sowas wie "...pointer to function makes pointer from integer without a cast"... also doch nicht ganz glücklich gelöst.
Das ist _ausschließlich_ ein Problem "Implementation". Der GCC unterstützt Makros mit variablen Argumenten und dieses Feature wird von den Inlines verwendet. Die Argumente werden in ein ULONG-Array gepackt. Und genau das ist die Stelle, an der die Warnung kommen _muß_. Die beschriebene Methode ist äußerst ineffizient. Deshalb empfehle ich generell mit NO_INLINE_STDARG zu arbeiten. Zum einem gibt es dann keine Warnung und außerdem ist der generierte Code dann um Längen besser.

Naja, im Groben habe ich das auch gesagt. "Es gibt ja immer noch die Stubs" ;)

Zitat:
Zitat:
Sei mir bitte nicht böse, aber Konstanten verwende ich z.B. eher selten im Zusammenhang mit IText. Da kommen höchstens Texte hinein, die mir die locale.library liefert, und diese Strings sind nur scheinbar konstant...
Irrelevant. Der Texteintrag in IText kann trotzdem ein "const" haben und Du kannst dennoch Deinen const-losen Typ zuweisen.

Habe ich ja auch nicht bestritten. Weiter unten in dem Post habe ich aber auch gesagt, daß die IText-Struktur zur _Wiederverwendung_ gedacht war und das wäre mit nem CONST UBYTE * als Member nun mal unmöglich. Einmal zugewiesen, nie mehr verändert.

Angenommen, Du schreibst ein Programm, daß innerhalb einer Schleife mehrere Texte via Intuition ausgeben soll und es steht Dir für den Zweck nur die IText-Struktur zur Verfügung. Die Ausgabeschleife könntest Du somit abhaken, wenn IText eine String-Konstante als Member hätte. Oder wolltest Du etwa versuchen, die IText-Struktur jedesmal zu redefinieren? I-)

Man sollte evtl. auch bedenken, daß es innerhalb eines OS auch historisch gewachsene Strukturen geben kann. Das beißt sich halt manchmal mit den hehren Ansprüchen einer moderneren Entwickler-Gruppe I-)

Zitat:
Zitat:
Streng genommen bräuchte man den jeweiligen String nie konstant zu definieren.
Weisst Du eigentlich wie const funktioniert und was es aussagt? :-(

Soweit ich weiß, dient const dazu, eine Variable über den Ablauf des Programms hinweg unveränderbar zu halten, sowohl im Programm selbst als auch in bspw. Funktionen in Bibliotheken. Also zu verhindern, daß der jeweilige Wert absichtlich oder unabsichtlich manipuliert wird.

Das ist bei gewissen Daten wohl sinnvoll, aber bei dem Text eines Fenster- oder Screentitels? Oder bei Texten in Gadgets? Oder gar bei dem Text, der sich per Default (Convenience!) in einem String-Gadget befindet???

Ich glaube, Du hast meinen Post etwas falsch verstanden. Ich verstehe durchaus, wo die Probleme der C++-Entwickler liegen und es ließen sich sicherlich auch Lösungen dafür finden.

Im Fall der IText-Struktur wäre es aber witzlos, in einer neuen OS-Version Rücksicht auf die enorme Typstrenge der C++-Compiler zu nehmen. Das geht auch anders. C-Programmierer müssen sich auch dann und wann behelfen, einen Wrapper basteln z.B. Das können die C++-Jünger doch wohl auch, oder nicht?

Wenn jemand unbedingt IText im Zusammenhang mit Konstanten und C++ benutzen möchte, kann er sich doch eine Wrapper-Funktion basteln, die den Inhalt der übergebenen Konstanten kopiert und die Kopie dann in IText einträgt. Dann sollte alles seine Richtigkeit haben. Die Konstante wird nicht angetastet und IText ist ohne Cast benutzbar. Und um die Casterei gings doch ursprünglich.

Wie ich weiter oben schon sagte: Im AmigaOS gibts vieles, was historisch gewachsen ist und zu einer Zeit entstand, als man von strenger Typprüfung eines C++-Compilers noch nicht allzu viel Ahnung hatte.

Weißt Du, ich frage mich oft, ob diejenigen, die sich über die Merkwürdigkeiten im AmigaOS heute so schön mokieren, _nicht_ die gleichen Entscheidungen wie die Commodore-Entwickler damals getroffen hätten.

Ehrlich gesagt: Das glaube ich weniger.

Ich fasse das Ganze mal so zusammen: Manchmal sind die Casts nicht schön, aber wer den alten Krempel in AmigaOS benutzen will, wird sich wohl oder übel damit anfreunden müssen.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233


[ Dieser Beitrag wurde von whose am 10.08.2005 um 11:56 Uhr editiert. ]

[ - Answer - Quote - Direct link - ]

2005-08-10, 11:57 h

Solar
Posts: 3680
User
Zitat:
Original von whose:
Zitat:
Zitat:
Streng genommen bräuchte man den jeweiligen String nie konstant zu definieren.
Weisst Du eigentlich wie const funktioniert und was es aussagt? :-(

Soweit ich weiß, dient const dazu, eine Variable über den Ablauf des Programms hinweg unveränderbar zu halten, sowohl im Programm selbst als auch in bspw. Funktionen in Bibliotheken. Also zu verhindern, daß der jeweilige Wert absichtlich oder unabsichtlich manipuliert wird.


So weit korrekt.

Zitat:
Das ist bei gewissen Daten wohl sinnvoll, aber bei dem Text eines Fenster- oder Screentitels?

Kann es sein, das du hier

const <type> * x // Zeiger auf Konstante

und

<type> * const y // konstanter Zeiger

verwechselst?

Und es geht hier nicht um die Bequemlichkeit von C++-Proggern, sondern um hinzugekommene Möglichkeiten der Fehlerüberprüfung. Wenn Du dem ohnehin schon kruden Register-Ping-Pong des AmigaOS noch eine Wrapperschicht hinzufügen willst, gehört die in's OS, statt jeden Entwickler selbst vor die Aufgabe (oder Unmengen Compilerwarnungen) zu stellen.

Heute programmiert außerhalb des Amiga-Sektors kaum noch jemand ganze Anwendungen in C...


[ Dieser Beitrag wurde von Solar am 10.08.2005 um 12:00 Uhr editiert. ]

[ - Answer - Quote - Direct link - ]

2005-08-10, 15:54 h

gni
Posts: 1106
User
Zitat:
whose:
Zitat:
gni:
Die VarArgs-Varianten sind nur _Hilfsfunktionen_ ("convenience")!

Genau. Und davon schrieb ich einen Post vorher. Das vieles, was einem heute in den Includes merkwürdig vorkommen mag, damals dazu gedacht war, den externen Entwicklern das Leben zu erleichtern.
Die Funktionen haben schon einen Sinn: So kann man bequemer variable Taglisten erzeugen, dh. was hinzunehmen bzw. weglassen ohne einen Index anpassen zu müssen. Motif hat im übrigen auch solche Funktionen.
Zitat:
Zitat:
Beim Füllen der TagList mußt Du _auch_ Casten.
Eben. Deswegen sagte ich ja auch, daß das keine besonders glückliche Lösung war mit den Taglisten.
Das sehe ich anders. Es ist bei weitem flexibler und kann ohne größere Anstrengung verändert werden. Das war mit den alten Strukturen nicht möglich. Und wie bereits gesagt, auch Motif verwendet "TagListen" und das gibt es für viele Systeme.
Zitat:
Die Inlines/Stubs bauen noch dazu auf einer Eigenschaft auf, die nicht auf jeder Maschine garantiert sein muß.
Ich sehe da das Problem nicht. Inline/Stubs sind maschinen- und Compilerspezifisch. Solange "sizeof(long) == sizeof(long*)" gilt, gibt es kein Problem.
Zitat:
Zitat:
Zitat:
Da kommt dann sowas wie "...pointer to function makes pointer from integer without a cast"... also doch nicht ganz glücklich gelöst.
Das ist _ausschließlich_ ein Problem "Implementation". Der GCC unterstützt Makros mit variablen Argumenten und dieses Feature wird von den Inlines verwendet. Die Argumente werden in ein ULONG-Array gepackt. Und genau das ist die Stelle, an der die Warnung kommen _muß_. Die beschriebene Methode ist äußerst ineffizient. Deshalb empfehle ich generell mit NO_INLINE_STDARG zu arbeiten. Zum einem gibt es dann keine Warnung und außerdem ist der generierte Code dann um Längen besser.
Naja, im Groben habe ich das auch gesagt. "Es gibt ja immer noch die Stubs" ;)
Es ging um die Warnung und wie sie zu Stande kommt.
Zitat:
Weiter unten in dem Post habe ich aber auch gesagt, daß die IText-Struktur zur _Wiederverwendung_ gedacht war und das wäre mit nem CONST UBYTE * als Member nun mal unmöglich. Einmal zugewiesen, nie mehr verändert.
Siehe Solars Posting: Es kommt auf die Platzierung von const an.
Zitat:
Im Fall der IText-Struktur wäre es aber witzlos, in einer neuen OS-Version Rücksicht auf die enorme Typstrenge der C++-Compiler zu nehmen.
Das Problem ist _nicht_ const. Das kann man einführen ohne das alte Quellen geändert werden müßten. Das Problem ist "UBYTE". Der "richtige/bessere" Typ wäre "char" in einem typedef gewesen.
Zitat:
Wie ich weiter oben schon sagte: Im AmigaOS gibts vieles, was historisch gewachsen ist und zu einer Zeit entstand, als man von strenger Typprüfung eines C++-Compilers noch nicht allzu viel Ahnung hatte.
Stringkonstanen haben einen Typ: "char*". Den meisten C Compilern ist bis heute egal, ob man das einem "passendem" Charactertyp zuweist. C++ hat da schon immer draufgeschaut und GCC 4.0 warnt auch im C Mode.
Zitat:
Ich fasse das Ganze mal so zusammen: Manchmal sind die Casts nicht schön, aber wer den alten Krempel in AmigaOS benutzen will, wird sich wohl oder übel damit anfreunden müssen.
So ganz richtig ist das nicht. Das API macht Probleme mit C++. Mit einem entsprechenden C Compiler bekommt man neuerdings auch Warnungen bezüglich Zeigervorzeichen. Auch wenn das AMiga API Schwächen hat, kann man oft Casts vermeiden. Viele sind nur zu faul es zu tun und unglücklicherweise enthalten viele Beispiele Casts :-(

[ Dieser Beitrag wurde von gni am 10.08.2005 um 17:08 Uhr editiert. ]

[ - Answer - Quote - Direct link - ]

2005-08-10, 15:57 h

Holger
Posts: 8116
User
Zitat:
Original von whose:
Die Funktionen, die die Taglisten als VarArg-Parameter akzeptieren (und genau dafür sind die Taglisten gedacht!),

Sind sie nicht. Varargs-Funktionen sind eine Hilfsmittel für C/C++ -Programmierer und nicht des Betriebssystems.
TagLists bieten im Gegensatz dazu u.a. die Möglichkeit, dynamisch aufgebaute Listen mit statischen zu verlinken, eine Möglichkeit, die von C-Programmierern fast nie benutzt wird, obwohl sie das Kopieren von 90% aller konstanten Argumente auf den Stack einsparen würde.
Es sieht aber im typischen C-Quellcode komplizierter aus.
Zitat:
Sei mir bitte nicht böse, aber Konstanten verwende ich z.B. eher selten im Zusammenhang mit IText. Da kommen höchstens Texte hinein, die mir die locale.library liefert, und diese Strings sind nur scheinbar konstant...
Abgesehen davon, daß ich genau diese Benutzung von OS1.x IText-Strukturen und OS2.1/3.0 locale.library in ein und demselben Programm für unwahrscheinlich gehalten habe:
Strings, die von der locale.library geliefert werden, sind konstant. In diese strings reinzuschreiben, wäre ein unverzeihlicher Programmierfehler.
Zitat:
Das Dumme ist nur, daß die entsprechende Funktion genau das _nicht_ tut. Sie erwartet als Parameter einen Zeiger auf die IText-Struktur, nicht auf den darin enthaltenen String.
Genau, gerade diese Funktion könnte den gesamten Parameter zusätzlich auch noch als const deklarieren. Sollte sie dann auch.
Zitat:
Das ist allerdings richtig. Die signed/unsigned-Geschichten bei manchen Parametern habe ich auch schon öfter verflucht (bzw. das fest eingebaute "-traditional" des StormC-GCC). Sieht man das aber geschichtlich, wird deren Anwendung wieder verständlich. Effizienz in Sachen Speicherverbrauch. Das Zeugs hatte und hat schon seinen Sinn...
Kann ich nicht nachvollziehen. signed/unsigned ändert nichts am Speicherverbrauch. Und z.B. die Größe einer Datei/eines Datenträger mit signed zu deklarieren, kann ich nur als grundsätzlichen Fehler ansehen. Heute spielt das vielleicht keine Rolle mehr, ob ein Programm eine 2GB oder eine 4GB Grenze besitzt, weil beides Mist ist, aber es gab ein paar Jahren, in denen genau das relevant war.
Abgesehen davon, daß ein Programm, das vom System eine maximale positive Zahl geliefert bekommen würde, sich immer noch besser verhalten würde, also eines, daß mit negativen Werten weiterrechnet.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ Dieser Beitrag wurde von Holger am 10.08.2005 um 16:03 Uhr editiert. ]

[ - Answer - Quote - Direct link - ]

2005-08-10, 16:56 h

Amaris
Posts: 941
User

So...jetzt will ich mal versuchen meinen Thread wieder zurückzuerobern
:P

Hab nämlich noch eine andere Frage zu dem schon genannten Programm, also
http://www.amaris.de.vu/main.c


Dort wird die Funktion OpenWindowTags() benutzt um ein Fenster zu öffnen. Nun hatte ich gerade mal ein bißchen Zeit mir die neulich bestellte "Amiga Developer CD" anzuschauen.
Dort finde ich jedoch keine Beschreibung der genannten Funktion!
OpenWindowTagList() ist alles was ich finde, jedoch nicht OpenWindowTags().

Ich habe außerdem vor Kurzem ein gebrauchtes Buch erstanden, namens "Amiga - Systemprogrammierung in C" (dürfte von 1986 sein). Dort wird auch eine Struktur namens NewWindow benutzt um die Eigenschaften des Fensters zu definieren und eine Funktion namens OpenWindow() um es zu öffnen.

Leider habe ich eigentlich nicht die geringste Ahnung von der Amiga-API
und bin (wie schon mal gesagt) auch in C / C++ allgemein noch äußerst unerfahren. Daher kann ich damit jetzt auch nicht viel anfangen. Gibt es soviele verschiedene Möglichkeiten ein Fenster zu öffnen?

MfG
Amaris



--
-Amiga 1200, 68030 @ 50 Mhz, 4 GB HDD, 16 MB RAM, externes PCMCIA-CD-ROM-Laufwerk

[ - Answer - Quote - Direct link - ]

2005-08-10, 17:12 h

DariusBrewka
Posts: 899
[Banned user]
OpenWindowTags() & OpenWindowTagList() sind "identischen" Funktionen, jedoch gibst du der ersten die Tags mit in den Funktionsaufruf bei der zweiten musst du einen Zeiger auf eine Tagliste übergeben.

code:
win = OpenWindowTags(NULL,
	  WA_Left,            x0,
	  WA_Top,             y0,
	  TAG_DONE);


oder

code:
struct TagItem WinTags[] = {
     WA_Left,	 0,
     WA_Top, 	 0,
     TAG_DONE
   }

   win = OpenWindowTagList(NULL, WinTags);


die zweite Version ist eigentlich besser (Argumente werden nicht auf den Stack kopiert (s.Holger oben)) , wird aber meistens aus Konfort-gründen wohl nicht genutzt (ist halt einfacher).


[ Dieser Beitrag wurde von DariusBrewka am 10.08.2005 um 17:13 Uhr editiert. ]

[ - Answer - Quote - Direct link - ]

2005-08-10, 17:26 h

Holger
Posts: 8116
User
Zitat:
Original von DariusBrewka:
code:
struct TagItem WinTags[] = {
     WA_Left,	 0,
     WA_Top, 	 0,
     TAG_DONE
   }
   win = OpenWindowTagList(NULL, WinTags);


die zweite Version ist eigentlich besser (Argumente werden nicht auf den Stack kopiert (s.Holger oben)) , wird aber meistens aus Konfort-gründen wohl nicht genutzt (ist halt einfacher).

Na ja, nur wenn WinTags keine lokale Variable ist, sonst liegt sie ja doch auf dem stack. Aber typischerweise hat man eine ziemlich lange Liste von unveränderlichen Eigenschaften und einige wenige dynamische

code:
struct TagItem ConstWinTags[] = {
     WA_Left, 0,
     WA_Flags,	 ...,
     WA_IDCMP, 	 ...,
     WA_ScreenTitle, appName,
     WA_Backfill, myBackfillHook,
     WA_MenuHelp, TRUE,
     WA_NewLookMenus, TRUE,
     WA_NotifyDepth, TRUE
     WA_PointerDelay, TRUE
     TAG_DONE
   };

 void openAppWindow()
 {
   struct TagItem DynWinTags[] = {
     WA_Gadgets, gadgetList,
     WA_InnerWidth,  calculatedWidth,
     WA_InnerHeight, calculatedHeight,
     WA_Title,   localizedWinTitle
     WA_IDCMP, 	 ...,
     WA_
     TAG_MORE, ConstWinTags
   };
   win = OpenWindowTagList(NULL, WinTags);


So in der Art.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2005-08-10, 17:40 h

Holger
Posts: 8116
User
Zitat:
Original von whose:
Die Inkonsistenzen bei OpenLibrary() und CloseLibrary() haben wir eigentlich nur der dos.library zu verdanken. Die tanzte als erste aus der Reihe, was den Struktur-Typ betrifft (bzw. die notwendige Erweiterung der Library-Struktur).

Das die libraries intern immer Erweiterungen der Basis-Struktur darstellen, ist klar. Aber warum man dann die Pointer der Anwendung anpassen muß, insb. bei libraries, auf deren Daten man ja gar nicht zugreifen sollte, ist unklar.
Es ist auch nicht so einfach, auf die schneller ein paar Beispiele herauszusuchen, die Probleme machen. Da fehlt mir der brauchbare Suchalgorithmus.
Sofort gefunden wird:
APTR CreateIORequest( CONST struct MsgPort *port, ULONG size );
im 3.5 API.
Ein generisches Beispiel ist
APTR AllocAslRequest( ULONG reqType, struct TagItem *tagList );
das liefert zwar unterschiedliche Strukturen zurück, aber die gemeinsamen Daten hätte man in eine Basis-Strukture verpacken können. Oder eine Struktur mit einem union für die Dinge, die unterschiedlich sind.
Noch besser wäre natürlich eine Funktion zum Auslesen und ein vollständiges Kapseln der Requester-Struktur gewesen.
Zitat:
Die anderen Fälle (mir fällt jetzt gerade nichts konkretes ein, aber da gabs noch ein paar, soweit ich mich erinnere) gehen auf Unstimmigkeiten bei der Nomenklatur zurück und tauchen dementsprechend auch nur in den Includes auf. Die Typen bei OpenLibrary() und CloseLibrary() sind aber korrekt.
Nun, unabhängig von der Frage nach der Korrektheit fällt auf, daß es hunderte von Datentypen gibt, deren interna's zwar versteckt werden sollen (was ja gut ist), deren API-Funktionen aber dann mit APTR (im Falle von DOS: BPTR) definiert sind, statt unvollständige Struktur-Deklarationen zu benutzen, die eine Typsicherheit ermöglichen würden, ohne internas zu kompromittieren.
So kann man z.B, in der DOS-Library FileHandles und FileLocks wunderbar verwechseln, viele Funktionen laden gerade dazu ein, und kein Compiler wird jemals warnen.
Und der große Witz daran: die internen Strukturen sind trotzdem bekannt und dokumentiert...

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2005-08-10, 17:48 h

Holger
Posts: 8116
User
Zitat:
Original von gni:
Auch wenn das AMiga API Schwächen hat, kann man oft Casts vermeiden. Viele sind nur zu faul es zu tun und unglücklicherweise enthalten viele Beispiele Casts :-(

Und zwar auch die bei der Dokumentation beiliegenden. Wenn es aber schon gar keine Beispiele ohne eine Haufen casts gibt und eben selbst die Beispiel-Lieferanten aufgrund einiger notwendiger casts gleich pauschal überall typecasts einfügen, wird auch niemand erfahren, wie es ohne funktioniert.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2005-08-10, 23:09 h

whose
Posts: 2156
User
@Holger:

Da hast Du zweifellos Recht. Andererseits sind Deine Beispiele auch Beispiele dafür, was aus einer geschichtlichen Entwicklung heraus entsteht (besonders die ASL-Geschichte). Sicher wird man sich auch mit OS4 stundenlang über die seltsamen Deklarationen aufregen können, es ändert aber nichts daran, daß sie so sind, wie es geschrieben steht ;)

Wenn Neuerungen eingeführt werden, sollte man dann auch zusehen, daß die Verwendung der Neuheiten gefördert und die Verwendung der "Altlasten" entmutigt wird. Dazu sollten die Neuheiten aber auch einen konkreten Sinn haben, den man den Entwicklern auch erläutern sollte. Mich als C-Programmierer z.B. würde eine API-Verbesserung nur mit Hinblick auf eine "sicherere" Typüberprüfung durch den Compiler nicht wirklich locken. Wenn ich durch die Verbesserung allerdings weniger Arbeit habe _und_ der Compiler noch dazu auf mehr potentielle Fehler hinweist, _das_ wäre ein echtes Argument.

Wie wäre es denn mit einer neuen Form der amiga.lib, die, neben Arbeitshilfen der modernen Art, die Typecast-Fallen für C++-Programmierer beseitigt oder wenigstens abmildert?

Damit wäre den C++-Programmierern deutlich mehr geholfen als mit "Panikmache" (das ist jetzt nicht so stark gemeint, wie es klingt. Aber manchmal habe ich den Eindruck, Du wolltest angehende C++-Programmierer auf jeden Fall davon abhalten, die AmigaOS-API zu benutzen. Möglicherweise einfacher für die betreffenden Leute, aber nicht gut für AmigaOS meiner Meinung nach).

Abgesehen davon: aus Fehlern lernt man im Allgemeinen und ich kann von mir sagen, daß mich das Programmieren unter AmigaOS bedeutend weiter gebracht hat als jeder Uni-Standard-Kurs. Zumindest sehe ich potentielle Fallen deutlich eher als meine ehemaligen Kollegen, die stur nach gängiger Praxis "narrensicher" Programmieren mit strenger Typprüfung gelernt haben. Die verlassen sich zu sehr darauf, daß der Compiler schon warnt, wenn Ungemach droht. Meist tut er das ja, manchmal aber eben auch nicht.

Naja, lange Rede, kurzer Sinn: Das AmigaOS-API ist, wie es ist. Nicht perfekt, aber wenn man sich dran gewöhnt hat nett zu benutzen. Trotz der Ungereimtheiten mit einigen Strukturen.

Grüße



--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Answer - Quote - Direct link - ]

2005-08-10, 23:21 h

Holger
Posts: 8116
User
Zitat:
Original von whose:
Wie wäre es denn mit einer neuen Form der amiga.lib, die, neben Arbeitshilfen der modernen Art, die Typecast-Fallen für C++-Programmierer beseitigt oder wenigstens abmildert?

Eine sinvoller typisierte Version, sowohl der header, als auch der amiga.lib wäre bestimmt sinnvoll, auch für C nicht nur für C++.

Allerdings hauptsächlich für Entwickler, die neue Projekte starten wollen. Alter Code läuft damit dann natürlich erstmal nicht.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2005-08-10, 23:39 h

whose
Posts: 2156
User
Zitat:
Original von Solar:

Zitat:
Das ist bei gewissen Daten wohl sinnvoll, aber bei dem Text eines Fenster- oder Screentitels?

Kann es sein, das du hier

const <type> * x // Zeiger auf Konstante

und

<type> * const y // konstanter Zeiger

verwechselst?

Und es geht hier nicht um die Bequemlichkeit von C++-Proggern, sondern um hinzugekommene Möglichkeiten der Fehlerüberprüfung. Wenn Du dem ohnehin schon kruden Register-Ping-Pong des AmigaOS noch eine Wrapperschicht hinzufügen willst, gehört die in's OS, statt jeden Entwickler selbst vor die Aufgabe (oder Unmengen Compilerwarnungen) zu stellen.


Oder halt in eine Compilerbibliothek. Aber die Mühe macht sich natürlich niemand, Jammern ist leichter...

Also: Mit dem Zeiger auf die Konstante hätte man nichts gewonnen, mit dem konstanten Zeiger alles verloren (nein, ich habe nichts verwechselt). Wo liegt da der echte Vorteil einer const-Deklaration? Der Zeiger auf die Konstante läßt zwar den Wechsel des Zeigers zu und vermeidet eine Warnung des Compilers, macht aber im Zusammenhang mit IText nichts sicherer. Spätestens, wenn Assembler ins Spiel kommt hat sich das Thema Sicherheit sowieso erledigt (ich weiß, heute verwendet niemand mehr Assembler, außer den paar Amiga-Freaks. Aber ging es nicht gerade um diese?)

Wie ich schon ausführte, kommen die meisten Strings, welche mittels IText ausgegeben werden, aus einer dynamischen Umgebung. Ratet doch alle mal, welche Struktur innerhalb von Intuition von Anfang an exzessiv eingesetzt wurde, wenns um GUI-Texte ging? Kommen da heute noch echte Konstanten vor? Seit der locale.library? Sicherheit schön und grün, man kanns aber damit auch übertreiben.

Daher bin ich auch immer noch der Meinung, daß man speziell für Konstanten (und mit Hinblick auf strenge Typüberprüfung) eine Wrapperfunktion bauen sollte, die auf die const-Eigenschaft Rücksicht nimmt und intern meinetwegen IText einsetzt. Damit wären alle glücklich. Die C++-Programmierer können ihrer Paranoia frönen und die C-Programmierer wie gehabt selbst auf die Fallen achten, die der Compiler mit viel Geschrei ankündigt. Man sollte nicht immer voraussetzen, daß das, was einem selbst gefällt, jedem anderen auch zu gefallen hat. Es gibt sicher noch genug Leute, die eigentlich keine Triebe haben, etwas in C++-Manier zu entwickeln, selbst wenn sie berulich dazu gezwungen sind.

Zitat:
Heute programmiert außerhalb des Amiga-Sektors kaum noch jemand ganze Anwendungen in C...

Sind diese Anwendungen wirklich sicherer als früher? Oder meinen die Entwickler das nur?

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233


[ Dieser Beitrag wurde von whose am 10.08.2005 um 23:56 Uhr editiert. ]

[ - Answer - Quote - Direct link - ]

2005-08-10, 23:50 h

whose
Posts: 2156
User
Zitat:
Original von Holger:
Zitat:
Original von whose:
Wie wäre es denn mit einer neuen Form der amiga.lib, die, neben Arbeitshilfen der modernen Art, die Typecast-Fallen für C++-Programmierer beseitigt oder wenigstens abmildert?

Eine sinvoller typisierte Version, sowohl der header, als auch der amiga.lib wäre bestimmt sinnvoll, auch für C nicht nur für C++.

Allerdings hauptsächlich für Entwickler, die neue Projekte starten wollen. Alter Code läuft damit dann natürlich erstmal nicht.


Naja, man muß ja das Altbewährte nicht gleich komplett über den Haufen schmeißen. Eine andere Möglichkeit wäre eine "sozusagen" alib2, mit dem Hinweis versehen, daß man neue Projekte doch bitte nur gegen diese Lib linkt.

Die Leute, die auf Biegen und Brechen mit den alten Methoden arbeiten wollen, tun es sowieso, die via "modernisierter" API zu erziehen hat noch nie wirklich hingehauen. Und die, die Ihren Vorteil in der neuen Lib sehen, werden sie dann auch nutzen. Allerdings müßte die Lib erst einmal gebaut werden...

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Answer - Quote - Direct link - ]

2005-08-11, 21:50 h

Holger
Posts: 8116
User
Zitat:
Original von whose:
Naja, man muß ja das Altbewährte nicht gleich komplett über den Haufen schmeißen. Eine andere Möglichkeit wäre eine "sozusagen" alib2, mit dem Hinweis versehen, daß man neue Projekte doch bitte nur gegen diese Lib linkt.

Natürlich, so meinte ich das ja auch. Es ist eben ein entweder-oder. Das heißt, für Entwickler, die ein altes Projekt nicht komplett umstellen wollen, ergibt sich daraus kein Vorteil.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Answer - Quote - Direct link - ]

2005-08-11, 22:05 h

Holger
Posts: 8116
User
Zitat:
Original von whose:
Also: Mit dem Zeiger auf die Konstante hätte man nichts gewonnen, mit dem konstanten Zeiger alles verloren (nein, ich habe nichts verwechselt).

Doch, Du hast es noch immer nicht begriffen. Die Compiler-Warnung wurde erzeugt, weil ein Zeiger auf unveränderlichen Text in einer Variable kopiert wurde, deren Datentyp Zeiger auf veränderbaren Text ist.
Zitat:
Wo liegt da der echte Vorteil einer const-Deklaration? Der Zeiger auf die Konstante läßt zwar den Wechsel des Zeigers zu und vermeidet eine Warnung des Compilers, macht aber im Zusammenhang mit IText nichts sicherer. Spätestens, wenn Assembler ins Spiel kommt hat sich das Thema Sicherheit sowieso erledigt (ich weiß, heute verwendet niemand mehr Assembler, außer den paar Amiga-Freaks. Aber ging es nicht gerade um diese?)
Das hat überhaupt nichts mit Assembler zu tun. Auch in C++ kann man per const_cast den Datentyp wieder ändern. Es geht darum, daß das AmigaOS, das sowieso nicht in C++ geschrieben ist, Dir die Garantie gibt, daß Rendering-Routinen, denen Du eine IText-Struktur übergibst, die String-Daten nicht verändern.
Eine const Deklaration ist nur das Mittel, mit dem der OS-Entwickler dem Compiler mitteilt, daß es diese Garantie gibt, so daß der dafür sorgen kann, daß der Anwendungsentwickler (Du) keine Dokumentation mehr aufschlagen mußt, um das herauszufinden. Und vor allem damit Du keine Fehlersuche mehr machen mußt, wenn eine OS-Routine in den String schreiben würde.
Zitat:
Wie ich schon ausführte, kommen die meisten Strings, welche mittels IText ausgegeben werden, aus einer dynamischen Umgebung. Ratet doch alle mal, welche Struktur innerhalb von Intuition von Anfang an exzessiv eingesetzt wurde, wenns um GUI-Texte ging? Kommen da heute noch echte Konstanten vor? Seit der locale.library? Sicherheit schön und grün, man kanns aber damit auch übertreiben.
Du hast es immer noch nicht begriffen.
1. Strings, die aus der locale.library kommen, sind Konstanten.
2. Du kannst einen veränderlichen String auch in einen const-Pointer schreiben.
Deine Ausführungen sind somit doppelt falsch. Das ergibt aber kein richtig.
Zitat:
Sind diese Anwendungen wirklich sicherer als früher? Oder meinen die Entwickler das nur?
Du verwechselt Typsicherheit mit Sicherheit. Es geht nicht darum, eine Anwendung sicherer zu machen. Die richtige Verwendung von const stellt nur eines sicher: Daß Du keine Fehler in der Form machst, daß Du einen unveränderliches Objekt einer Funktion gibst, die es verändert.
Einfaches Beispiel: daß Du einen string, den die locale.library liefert, nicht als Input-Buffer an Read() übergibst.

Selbstverständlich gibt es noch hundert anderer Fehlerquellen. Aber das ist eben besser als tausend Fehlerquellen.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ Dieser Beitrag wurde von Holger am 11.08.2005 um 22:08 Uhr editiert. ]

[ - Answer - Quote - Direct link - ]

2005-08-11, 23:38 h

whose
Posts: 2156
User
Zitat:
Original von Holger:
Zitat:
Original von whose:
Also: Mit dem Zeiger auf die Konstante hätte man nichts gewonnen, mit dem konstanten Zeiger alles verloren (nein, ich habe nichts verwechselt).

Doch, Du hast es noch immer nicht begriffen. Die Compiler-Warnung wurde erzeugt, weil ein Zeiger auf unveränderlichen Text in einer Variable kopiert wurde, deren Datentyp Zeiger auf veränderbaren Text ist.

Also nochmal:

Wir unterhalten uns über eine Sache, die lange, laaaange Zeit vor der allgemeinen Anerkennung heutiger Entwicklungsdogmen ihren Anfang nahm.

Zu dieser Zeit war es noch üblich, Speichersparend zu entwickeln, das schließt die Wiederverwendung einmal angelegter Buffer mit ein. Diese konnten im Quellcode durchaus auch ursprünglich in Form von Stringkonstanten deklariert worden sein.

Wenn die ehemaligen Commodore-Entwickler genau dieses taten (und sie taten es, einen zur Wiederverwendung vorgesehenen Puffer in Form einer Stringkonstanten zu definieren!), hätten sie sich selbst ins Knie geschossen, wenn sie bei einer Funktion, welche mit der IText-Struktur arbeitet, eine Unveränderbarkeit eben dieses Puffers vorausgesetzt hätten. Dann hätte sie der eigene Compiler zeitweise quasi von der Arbeit ausgesperrt (Glaubst Du jetzt endlich, daß ich den Unterschied zwischen einem Zeiger auf eine Stringkonstante und einem konstanten Zeiger auf einen String (der durchaus auch eine Konstante sein kann) kenne?).

Das ist vom heutigen Standpunkt aus gesehen zwar übelster Pfusch am Bau, aber ich rede eben nicht von heutigen Standpunkten.

Deswegen ja auch meine Anregung, die damals angefangenen Tricksereien an heutige Gepflogenheiten anzupassen, eben in der Form einer neuen amiga.lib. Damit kann man dann prima nach heutigen Gepflogenheiten entwickeln und mit der Zeit die "Sünden" von früher in Vergessenheit geraten lassen.

Ich war wohl etwas zu voreingenommen, was Du über das erste Kickstart weißt, sonst hätte ich das gleich genauer beschrieben, über welche Form von "Ausgabeschleife" ich rede.

Damit kommen wir auch gleich zum Thema "Sicherheit" und "Typsicherheit".

Ich weiß nicht, ob Dir bewußt ist, daß das erste Kickstart ein Mischmasch aus C- und Assemblercode war. Unabhängig davon, was heute in der großen EDV-Welt Standard ist, wird auch heute noch gern in Assembler geproggt, wo C oder gar C++ eigentlich angebracht wäre.

Mit dem Wissen im Hinterkopf, daß garantiert einer daher kommt, der die Typsicherheit einfach mittels Assembler oder einem alten Compiler aushebelt, macht sich kaum jemand die Mühe, Funktionen für C++-Progger narrensicher zu machen, sondern läßt die geliebten Tricksereien um des lieben Friedens willen zu.

Dadurch stellt sich auch die Frage nach der "Sicherheit" (Abstürze, Aushebelung von Sicherheitsmechanismen etc. pp.) eines Programms quasi nicht mehr, welche heutzutage ja ein wichtiges, aber durch die strenger Typisierung mancher Compiler lange nicht ausgestandenes Thema ist, wie Du sicher schon selbst erfahren hast.

Wieder "Lange Rede, kurzer Sinn": Eine für Euch C++-Progger sinnvollere Typisierung würde Euch zwar das Leben leichter machen, anderen wiederum nicht. Das diese Anderen pauschal Mist bauen, nur weil sie die Mechanismen, die zu Eurer Sicherheit eingebaut werden müßten, umgehen, ist etwas hart ausgedrückt.

Die meisten von denen wissen nämlich, was sie tun, und überlassen die Frage nach dem Sinn einer Aktion nicht so sehr dem Compiler wie es die C++Progger tun.

Genau so dachten damals übrigens die AmigaOS-Entwickler (C++ einfach durch C ersetzen).

Also sollte man nicht lange darüber lamentieren, was die Leute früher für "Mist" gebaut haben (der von deren Standpunkt aus gesehen alles andere als "Mist" war!), sondern Abhilfe für die heutzutage auftauchenden Probleme schaffen.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233


[ Dieser Beitrag wurde von whose am 11.08.2005 um 23:46 Uhr editiert. ]

[ Dieser Beitrag wurde von whose am 12.08.2005 um 00:15 Uhr editiert. ]

[ - Answer - Quote - Direct link - ]

2005-08-12, 00:10 h

whose
Posts: 2156
User
Zitat:
Original von Holger:

1. Strings, die aus der locale.library kommen, sind Konstanten.


Falsch. Diese Stringzeiger sind zwar als READ ONLY in den Autodocs kommentiert, aber nicht als Zeiger auf einen konstanten String deklariert (STRPTR, ohne CONST davor). Intern sind es sowieso keine Konstanten sondern ein veränderlicher Puffer, aus dem Du Deinen Text bis zur nächsten Verwendung von z.B. GetLocaleStr() herauskopieren kannst. In den meisten Fällen wird in einem Programm auch wieder ein und derselbe Stringpuffer verwendet, wenn dieser Text ausgegeben werden soll.

Schwupps! Spätestens jetzt hätte Dich Dein Compiler in den Hintern gebissen, wenn Du eine Erweiterung zur locale.library bauen wolltest, die auf eben diesen Puffer schreibend zugreifen muß und der wäre als CONST STRPTR deklariert.

Zitat:
2. Du kannst einen veränderlichen String auch in einen const-Pointer schreiben.
Deine Ausführungen sind somit doppelt falsch. Das ergibt aber kein richtig.


Allerdings kannst Du das nicht, wenn Du intern diese Struktur verwendest und dann versuchst, den Speicher dieses (konstanten!) Strings wiederzuverwenden. Da spielt ein const-Pointer, der nach außen zur Schau getragen wird, überhaupt keine Rolle. Ist zwar schlechter Stil, wurde aber so gemacht. Ursache bzw. Schützenhilfe war das zwiespältige Verhalten alter Compiler im Umgang mit "const". "const" haben sie beachtet, Zeiger auf Stringkonstanten alá 'outstr = "Wer das liest ist doof"' allerdings geflissentlich ignoriert.

Sieh es einfach so: In der täglichen Praxis werden die mittels IText übergebenen Strings zwar nicht verändert, die Commodore-Entwickler wollten das aber nicht garantieren. Punkt, aus.

Meine Ausführungen sind nicht falsch, Du bist nur zu sehr in modernem Denken versunken. Mir gings darum zu erklären, woher der Unfug kommt. Dir gehts darum, zu erklären, daß das Unfug ist. Aber das weiß ich schon eine ganze Weile und der Initiator dieses Threads hats gerade am eigenen Leib erfahren...

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233


[ Dieser Beitrag wurde von whose am 12.08.2005 um 00:44 Uhr editiert. ]

[ - Answer - Quote - Direct link - ]

2005-08-12, 09:22 h

Solar
Posts: 3680
User
Kinder, solange ihr von der Semantik von "const" keine Ahnung habt, und ernsthaft glaubt der Hauptzweck von C++ sei, "sicherere" Anwendungen zu schreiben, diskutiert doch besser nicht darüber, OK?

Wenn etwas durch eine Konstante initialisiert werden darf (weil es von den entsprechenden Funktionen nicht verändert wird), muß es auch "const" deklariert werden! Das hat nichts mit C++ zu tun und ist schon in C schlichtweg falsch - nur daß sich der Compiler nicht so sehr darüber beschwert.

Genau wie solche Sachen wie signed-Werte für Dateigrößen etc. - das hat nichts mit den "guten alten Zeiten" zu tun, sondern damit, das die Jungs damals unter Zeitdruck schlicht Fehler gemacht haben.

Und der Grund, warum heute kaum noch in C und hauptsächlich in C++ entwickelt wird, ist die bessere Wartbarkeit von C++-Code. (Wir gehen hier mal auf beiden Seiten von Leuten aus, die wissen, was sie tun.)


[ - Answer - Quote - Direct link - ]

2005-08-12, 10:29 h

gni
Posts: 1106
User
Zitat:
Solar:
Kinder, solange ihr von der Semantik von "const" keine Ahnung habt, und ernsthaft glaubt der Hauptzweck von C++ sei, "sicherere" Anwendungen zu schreiben, diskutiert doch besser nicht darüber, OK?

Schön das wenigstens einer Durchblick hat...
Zitat:
Wenn etwas durch eine Konstante initialisiert werden darf (weil es von den entsprechenden Funktionen nicht verändert wird), muß es auch "const" deklariert werden! Das hat nichts mit C++ zu tun und ist schon in C schlichtweg falsch - nur daß sich der Compiler nicht so sehr darüber beschwert.
Warum sollte ich bei 'char *foo = "ein string"' zwingend const brauchen?
Zitat:
Und der Grund, warum heute kaum noch in C und hauptsächlich in C++ entwickelt wird, ist die bessere Wartbarkeit von C++-Code.
Ach?

[ - Answer - Quote - Direct link - ]


-1- 2 3 [ - Post reply - ]


amiga-news.de Forum > Programmierung > Gleiches Programm wird von GCC kompiliert aber nicht von G++ ? [ - Search - New posts - Register - Login - ]


.
Masthead | Privacy policy | Netiquette | Advertising | Contact
Copyright © 1998-2024 by amiga-news.de - all rights reserved.
.