amiga-news ENGLISH VERSION
.
Links| Forum| Kommentare| News melden
.
Chat| Umfragen| Newsticker| Archiv
.

amiga-news.de Forum > Programmierung > Umsetzung StormC 4 -> gcc [ - Suche - Neue Beiträge - Registrieren - Login - ]

-1- [ - Beitrag schreiben - ]

24.04.2006, 20:40 Uhr

Uwe
Posts: 74
Nutzer
Ich versuche gerade ein größeres Projekt (Portierung von ScummVM)
von StormGCC auf gcc 2.95.3 umzusetzen.
Das scheint nicht ganz einfach zu sein. :-(

Scheinbar gibt es Unterschiede in der Implementierung
der ANSI-C-Bibliotheken. Ein Beispiel:

Im Programm kommen Stellen vor, bei dem versucht wird
0 Byte Speicher anzufordern (ist nicht meine Idee).

StormC liefert bei malloc(0) einen gültigen Zeiger.
gcc/ixemul stürzt bei einem malloc(0) ab, da laut
ixemul-Sourcen direkt auf AllocMem(0, ...) abgebildet
wird.

Gibt es noch andere Inkompatibilitäten, besonders
wie oben bei Grenzsituationen?

Gibt es Hinweise und Tipps, die eine "Umsetzung" erleichtern?

Uwe

PS: libnix funktioniert auch nicht
(fehlende Funktionen, weitere Inkompatibilitäten)

[ - Antworten - Zitieren - Direktlink - ]

24.04.2006, 22:50 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Uwe:
StormC liefert bei malloc(0) einen gültigen Zeiger.
gcc/ixemul stürzt bei einem malloc(0) ab, da laut
ixemul-Sourcen direkt auf AllocMem(0, ...) abgebildet
wird.

Kann so eigentlich nicht sein. Die bei malloc() belegte Größe wird für free() gepeichert. Also entweder wird auf AllocVec() gemappt, oder bei AllocMem() mind. 4 bytes für die Größeninformation zur Anforderung hinzugefügt. Im letzteren Fall dürfte es demzufolge kein Absturz geben.
Und im Falle von AllocVec hätte ich vermutet, daß es genauso funktioniert, weil ebenfalls mind. 4 bytes benötigt werden.
Zitat:
Gibt es Hinweise und Tipps, die eine "Umsetzung" erleichtern?
Neuere gcc-Version verwenden. Damit nicht bei einem späteren Wechsel neue Inkompatiblitäten auftreten. Außerdem ist der code, den Du portieren willst, bestimmt außerhalb der Amiga-Welt mit einem neueren gcc getestet worden.
Die gleiche Generation zu verwenden, kann viel Ärger ersparen.

mfg

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

[ - Antworten - Zitieren - Direktlink - ]

24.04.2006, 23:08 Uhr

Holger
Posts: 8116
Nutzer
Hab mal rasch den Test gemacht (AOS3.9)
AllocVec(0, ..) und AllocMem(0, ..) liefern NULL zurück (kein Absturz), AllocMem(4, ..) funktioniert erwartungsgemäß und malloc(0) übersetzt mit gcc3.4.0 liefert einen Pointer, wird also vermutlich wirklich auf AllocMem(x+4, ..) abgebildet.

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

[ - Antworten - Zitieren - Direktlink - ]

25.04.2006, 09:29 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Uwe:
StormC liefert bei malloc(0) einen gültigen Zeiger. gcc/ixemul stürzt bei einem malloc(0) ab, da laut ixemul-Sourcen direkt auf AllocMem(0, ...) abgebildet wird.

Gibt es wirklich einen Crash? Bei Allokationen <MINSIZE wird MINSIZE allokiert. Und nur Größen über einem bestimmten Limit werden direkt per AllocMem() bedient.
Zitat:
libnix funktioniert auch nicht (fehlende Funktionen, weitere Inkompatibilitäten)
Was fehlt? Welche weiteren Inkompatibilitäten? Zumindest liefert malloc(0) einen gültigen Zeiger, wenn ich die Quellen des libnix-malloc richtig lese. ixemul müßte laut Quellen auch einen gültigen Zeiger liefern. Davon abgesehen, Du willst garantiert für scummvm kein ixemul.

[ - Antworten - Zitieren - Direktlink - ]

25.04.2006, 19:39 Uhr

Uwe
Posts: 74
Nutzer
Ich habe noch mal genau nachgesehen.
Es war nicht malloc(0), sondern calloc(x,0).

Und nur bei libnix stürzt es ab.
Ich habe mir mal die libnix-Sourcen abgesehen
und etwas experimentiert.

code:
void *calloc(size_t nmemb,size_t size)
{
  size_t l;
  size_t *a;
  void *b;
  l=(nmemb*size+(sizeof(size_t)-1))&~(sizeof(size_t)-1);
  a=(size_t *)(b=malloc(l));
  if(b!=NULL)
  {
    do
      *a++=0;
    while((l-=sizeof(size_t))!=0);
  }
  return b;
}


Ist einer der Argumente 0 ist auch l = 0.
malloc(0) liefert einen gültigen Zeiger.
Danach wird vom Zeiger aus die nächsten 4 GB Speicher gelöscht.
l ist 0 und wird um 4 verringert (=4G-4) und auf 0 geprüft ...

Was bei libnix fehlte probiere ich nochmal aus.

[ - Antworten - Zitieren - Direktlink - ]

25.04.2006, 21:33 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Uwe:
C code:
void *calloc(size_t nmemb,size_t size)
{
  size_t l;
  size_t *a;
  void *b;
  l=(nmemb*size+(sizeof(size_t)-1))&~(sizeof(size_t)-1);
  a=(size_t *)(b=malloc(l));
  if(b!=NULL)
  {
    do
      *a++=0;
    while((l-=sizeof(size_t))!=0);
  }
  return b;
}


Wow, ja das ist C-Code der alte Schule. Immer nach dem Motto "je krypischer es aussieht, desto höher muß wohl die Performance sein".

Tja, irgendwann fällt so ein Mist jemanden auf die Füße, und wie so oft, jemanden, der nix dafür kann.

Gut, daß es OSS war und Du die Ursache gefunden hast.

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

[ - Antworten - Zitieren - Direktlink - ]

26.04.2006, 08:58 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Holger:
Wow, ja das ist C-Code der alte Schule.

Welche Stelle verstehst Du nicht?
Zitat:
Immer nach dem Motto "je krypischer es aussieht, desto höher muß wohl die Performance sein".
Woher nimmst Du diese Weisheit?
Zitat:
Tja, irgendwann fällt so ein Mist jemanden auf die Füße, und wie so oft, jemanden, der nix dafür kann.
Ein Glück wir haben "Experten" wie Dich :-/

[ - Antworten - Zitieren - Direktlink - ]

26.04.2006, 10:46 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von gni:
Welche Stelle verstehst Du nicht?

Ich versteh den code schon. Aber wie lange ich dafür gebraucht habe, steht in keinem Verhältnis zu dem, was er macht.
Zitat:
Zitat:
Immer nach dem Motto "je krypischer es aussieht, desto höher muß wohl die Performance sein".
Woher nimmst Du diese Weisheit?
Hallo? Willst Du jetzt nur aus Prinzip diskutieren?
Schau Dir doch bitte diesen Code mal an:
do
*a++=0;
while((l-=sizeof(size_t))!=0);

Statt einer for-Schleife benutzt man eine do-while Schleife, warum? Weil man eine Vortest einsparen wollte (was dann bei Uwe für den Absturz gesorgt hat)?
Statt einer for-Schleife mit einfachen Zähler benutzt man einen Dekrement -= und zwar innerhalb eines logisches Tests, warum? Weil es Performance bringt, im Quellcode vielleicht eine Zeile zu sparen?

Oder weil halt im Handbuch für esoterische Optimierungen steht "do..while ist schneller als for", "Dekrement in logischen Ausdruck einsetzen ist schneller, als in in eigene Anweisung zu schreiben", "Test auf 0 ist schneller als kleiner als" oder einfach nur "wenn's jemand auf Anhieb lesen kann, ist's zu langsam"?

Zitat:
Ein Glück wir haben "Experten" wie Dich :-/
Was hat das mit Experten zu tun?
Jeder Anfänger hätte geschrieben:

for(i=0; i<l; i++) a[i]=0;

und dieser Code hätte funktioniert und das wär auch auf Anhieb erkennbar gewesen. Vielleicht mit einem Promille weniger Performance, aber das was dieser Code an mehr Zeit benötigt hätte wäre immer noch ein Bruchteil dessen, was Uwe jetzt an Zeit investieren mußt, um den Fehler zu finden.

Fall jetzt immer noch jemand nicht versteht, warum es sinnvoll ist, lesbaren Code zu schreiben, werde ich nicht weiter mit ihm diskutieren.

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

[ - Antworten - Zitieren - Direktlink - ]

26.04.2006, 13:25 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Holger:
Statt einer for-Schleife benutzt man eine do-while Schleife, warum? Weil man eine Vortest einsparen wollte (was dann bei Uwe für den Absturz gesorgt hat)?

Offensichtlich hat vorher niemand 0-Bytes mit calloc() angefordert. IMHO ist das der wirkliche Bug.

[ - Antworten - Zitieren - Direktlink - ]

26.04.2006, 16:51 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von gni:
Offensichtlich hat vorher niemand 0-Bytes mit calloc() angefordert. IMHO ist das der wirkliche Bug.

Das ist wohl soweit vollkommen richtig.

Es ist trotzdem so, daß es für viele Aufgaben eine kanonische Art, es zu implementieren, gibt, wie man sie auch in jedem C-Lehrbuch finden kann.
Wie zum Beispiel die Trivialität, zum Iterieren über <was auch immer> eine for-Schleife zu verwenden.

Und mit dieser wäre der Fehler gar nicht erst passiert. Ich weiß, daß meine Vermutung, der Autor dieses Codes wäre von der üblichen Praxis aus Performance-Erwägungen abgewichen, reine Spekulation ist. Vieles spricht aber Angesicht der anderen Eigenheiten dafür, vor allem, da die zweitnaheliegenste Begründung, wenig C-Erfahrung, deutlich unwahrscheinlicher ist.

Ich habe letztendlich nur meinem Entsetzen beim Anblick des Stück Codes Audruck verliehen. Wenn andere weniger Unbehagen beim Betrachten dieses Fragments empfinden, was solls.

Ich persönlich bin froh, daß die AOS-Funktionen beim Anfordern von 0 bytes nicht mit einem Absturz reagieren. Ich denke, damit ist alles zu diesem Thema gesagt.

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

[ - Antworten - Zitieren - Direktlink - ]

26.04.2006, 21:36 Uhr

Dietmar
Posts: 166
Nutzer
@Holger:
> for(i=0; i<l; i++) a[i]=0;

Warum nicht:
code:
i = l;
while (i)
    a[--i] = 0;

In der Annahme, dass Vergleiche gegen 0 schneller sind, als in jedem Durchlauf i mit l zu vergleichen.

[ - Antworten - Zitieren - Direktlink - ]

27.04.2006, 09:10 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Dietmar:
Warum nicht:
code:
i = l;
while (i)
    a[--i] = 0;



Oder so?
code:
for(;l!=0;l-=sizeof(size_t))
 *a++ = 0;


[ - Antworten - Zitieren - Direktlink - ]

27.04.2006, 12:48 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Dietmar:
@Holger:
> for(i=0; i<l; i++) a[i]=0;

Warum nicht:
code:
i = l;
while (i)
    a[--i] = 0;

In der Annahme, dass Vergleiche gegen 0 schneller sind, als in jedem Durchlauf i mit l zu vergleichen.

Weil es relativ sinnlos ist, solche Annahmen zu machen. Ansonsten sind nunmal for-Schleifen das Konstrukt der Wahl, wenn man iterieren will. Das erhöht nicht nur die Lesbarkeit, sondern bietet auch dem Compiler besser Möglichkeiten, die Intention zu verstehen und zu optimieren. Wenn man überhaupt davon ausgeht, daß der Compiler guten Code erzeugen kann.

Andernfalls ist es egal, ob man mit 0 oder einem anderen Werte vergleicht, wenn der vom Compiler generierte Overhead zehnmal größer ist als dieser Unterschied.

Von daher ist gni's Variante besser:

for(;l!=0;l-=sizeof(size_t))
*a++ = 0;

weil sie Schleifenbedingung und zugehörige Dekrementanweisung da zusammenfaßt, wo sie hingehören.

Aber bei den meisten Prozessoren ist die Verwendung zweier Variablen, die beide in jedem Durchlauf verändert werden, aufwändiger als der Unterschied zwischen einem Test auf 0 und einem Vergleich. Somit ist folgendes besser:

for(b=a+l; a!=b; a++) *a=0;

Das reduziert die absolute Anzahl an Operationen, was i.A. mehr bringt als der Ersetzen eines Vergleichs durch einen Test auf 0. Allerdings ist der Effekt auf Prozessoren mit parallel arbeitenden Units sehr gering, nur der Schreibzugriff und der Vergleich können parallelisiert werden, aber beide Operationen müssen auf das Inkrement warten.

Dieses Problem kann mit Loop-Unrolling mit parallelisierbaren Anweisungen gelöst werden, aber es wäre sinnlos, das von Hand zu machen, weil die richtige Anzahl von "ausgerollten" Iterationen vom Zielprozessor abhängt und falsche Annahmen kontraproduktiv sind.

Beim 68k sind das eh maximal zwei integer Einheiten und die Load/Store Unit, die parallel arbeiten können. (Der Sprungbefehl wird vom Prozessor korrekt wegoptimiert...)

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

[ - Antworten - Zitieren - Direktlink - ]

27.04.2006, 16:36 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Original von Holger:
Aber bei den meisten Prozessoren ist die Verwendung zweier Variablen, die beide in jedem Durchlauf verändert werden, aufwändiger als der Unterschied zwischen einem Test auf 0 und einem Vergleich. Somit ist folgendes besser:

for(b=a+l; a!=b; a++) *a=0;

Am besten ist was ganz anderes: Man nehme bzero/memset, dann hätte es den Bug auch nicht gegeben. Aber genau die Funktionen sollten da vermieden werden.

[ - Antworten - Zitieren - Direktlink - ]

27.04.2006, 16:47 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von gni:
Am besten ist was ganz anderes: Man nehme bzero/memset, dann hätte es den Bug auch nicht gegeben. Aber genau die Funktionen sollten da vermieden werden.

Müssen die nicht auch innerhalb von libnix implementiert werden?
Vielleicht sollte man, wenn man schon dabei ist, da auch mal einen kritischen Blick drauf werfen...
Aber evtl. delegieren die auch nur an eine AOS-Funktion.

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

[ - Antworten - Zitieren - Direktlink - ]

27.04.2006, 18:04 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Holger:
Zitat:
Man nehme bzero/memset
Müssen die nicht auch innerhalb von libnix implementiert werden?
bzero nicht, aber beide sind vorhanden.
Zitat:
Vielleicht sollte man, wenn man schon dabei ist, da auch mal einen kritischen Blick drauf werfen...
Mach mal...
Zitat:
Aber evtl. delegieren die auch nur an eine AOS-Funktion.
Welche sollte das sein?

[ - Antworten - Zitieren - Direktlink - ]

27.04.2006, 21:42 Uhr

Uwe
Posts: 74
Nutzer
Bevor ihr euch weiter wegen Kleinigkeiten streitet,
hier ein noch gravierender Fehler bei libnix 2.1
(ältere Versionen habe ich nicht probiert).

code:
#include <stdio.h>

int main(int argc, char **argv)
{
    FILE *file1, *file2;
    int a,b;
    char buffer1[10];
    char buffer2[10];

    file1 = fopen("datei1", "rb");
    file2 = fopen("datei2", "rb");

    if (file1 && file2)
    {

        a = fread(buffer1, 1, 10, file1);

        b = fread(buffer2, 1, 10, file2);

        fclose(file1);
        fclose(file2);
    }

    return 0;
}


Ausgaben (im Code weggelassen):
a = 10;
buffer1 = (ersten zehn Bytes von file2, in Worten Zwei)
b = 0;

Das Öffnen der zweiten Datei scheint irgendwie
die File-Strukturen durcheinanderzubringen.
file1 scheint auf die zweite Datei zu zeigen.
file2 scheint ungültig zu sein (aber != NULL).

Das gleiche mit ixemul funktioniert.

Mal nebenbei:
Ich habe mal versucht die libnix-Bibliotheken neuzukompilieren:
Das makefile schlägt immer fehl:

make[1]: *** No rule to make target 'nrcrt0.S',
needed by 'nrcrt0.o'. Stop.

Version von make: 3.80
Version von gcc: 2.95.3

Nachtrag:
Ich habe mal das gleiche mit open/close/read probiert
und es funktioniert. Da fopen/fclose/fread darauf basieren
muss der Fehler dazwischen liegen.






[ Dieser Beitrag wurde von Uwe am 27.04.2006 um 22:07 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

27.04.2006, 22:52 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Uwe:
Bevor ihr euch weiter wegen Kleinigkeiten streitet,

Tun wir nicht, wir diskutieren nur ;)
Zitat:
C code:
file1 = fopen("datei1", "rb");
    file2 = fopen("datei2", "rb");

    if (file1 && file2)
    {
        fclose(file1);
        fclose(file2);
    }


Dir ist schon klar, daß das nicht ganz sauber ist?

Was den Fehler angeht, muß ich mir erstmal genauer ansehen...

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

[ - Antworten - Zitieren - Direktlink - ]

28.04.2006, 00:08 Uhr

Holger
Posts: 8116
Nutzer
@Uwe:
Also bei mir macht Dein Code das richtige. Habe gcc3.4.0 verwendet, kann also meinen Ratschlag nur noch mal bekräftigen: probier's mit 'ner neueren gcc-Version. Bzw. Umgebung, habe ja libnix und gcc aus ein und derselben Umgebung, vielleicht kann man die auch einzeln installieren, aber ich glaube nicht, daß sich der Aufwand manueller einzel-Installationen lohnt.

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

[ - Antworten - Zitieren - Direktlink - ]

28.04.2006, 09:04 Uhr

Stefan
Posts: 936
Nutzer
@Uwe:

Hallo Uwe,

Probiere doch mal den "GCC 3.4". Vielleicht klappt es damit
und mache hin ;) , damit es bald eine neue Scumm-Version gibt.

Der GCC 3 lässt sich parallel zur Version 2.95 betreiben.
Ich habe das auch so installiert und es funktioniert.
Auszug aus der 3.4.0-Notes

| - installation:
| To be able to use GCC 2.x and GCC 3.x at the same time, its
| recommended to install the frontend programs in bin/ with an
| added "3" eg. as gcc3.
| Executing an older GCC version from the V3 frontend is possible
| with -V<version> if the frontend for <version> is installed as
| gcc-<version>.


Gruß Stefan

:boing:




[ - Antworten - Zitieren - Direktlink - ]

28.04.2006, 20:31 Uhr

Uwe
Posts: 74
Nutzer
@Holger

Zitat:
Dir ist schon klar, daß das nicht ganz sauber ist?

Das sollte nur ein kurzes Beispiel sein.

@Holger, Stefan

Ich habe mal gcc 3.3 verwendet. Das gleiche.
Es liegt an libnix. Bei Version 1.2 geht es, ab 2.0 nicht mehr.
Ich habe 2.1 installiert gehabt.

Version 1.2 ist immer bei den gcc-Paketen dabei.
>2.0 gibt's auf der libnix-Homepage (bei Sourceforge.net).

Der Fehler muss also in der Version 2.0 hereingekommen sein.

MfG
Uwe

[ - Antworten - Zitieren - Direktlink - ]

29.04.2006, 10:38 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Uwe:
Ich habe 2.1 installiert gehabt.

Die basiert auf einer Beta-Version, die einige schwerwiegende Fehler hatte.
Zitat:
Version 1.2 ist immer bei den gcc-Paketen dabei.
Was neueres wurde auch nie offiziell rausgegeben.
Zitat:
>2.0 gibt's auf der libnix-Homepage (bei Sourceforge.net).
Das ist _nicht_ die Homepage von libnix. Es gibt keine.

[ - Antworten - Zitieren - Direktlink - ]


-1- [ - Beitrag schreiben - ]


amiga-news.de Forum > Programmierung > Umsetzung StormC 4 -> gcc [ - Suche - Neue Beiträge - Registrieren - Login - ]


.
Impressum | Datenschutzerklärung | Netiquette | Werbung | Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten.
.