Folgendes Programm laeuft nicht mit libc6 / gcc 2.5.3 fuer Strong ARM:
Es ist ein altes Beispiel aus den spaeten 80ern, daher noch kein
Prototyping.
[ ... ]
void errmsg(); /* Fehlermeldungen ausgeben */
[ ... ]
if (flg<0) { /* Radikand o.K. ? */
errmsg("Erkenne %s nicht als Zahl, Abbruch !",*(argv+1));
exit (ENUMB);
}
[ ... ]
/* VARARGS1 */
void errmsg(fmt)
char* fmt;
{
typedef va_list vptype;
vptype adr;
char str[320+1];
int l;
adr=(vptype)&fmt+sizeof(fmt);
l=sprintf(str,"%s: ",prcn);
(void)vsprintf(str+l,fmt,adr);
(void)fprintf(stderr,"%s\n",str);
}
Ergebnis: Der 'vsprintf' verursacht entweder Segfaults oder SIGBUS,
je nachdem, ob mit '-O3' compiliert wurde oder nicht.
Das Programm laeuft unter verschiedenen Unix-Dialekten und auch
unter x86-Linux, nur halt nicht auf der ARM-Plattform.
Gibt es Besonderheiten bei der Parameteruebergabe ?
Gruss,
--
Hans Bonfigt /SES/
UNIX App. Development Systementwicklung Schollmeier
Phone: +49 171 3758928 <bonfigt....@t-online.de>
> /* VARARGS1 */
> void errmsg(fmt)
> char* fmt;
> {
> typedef va_list vptype;
>
> vptype adr;
> char str[320+1];
> int l;
>
> adr=(vptype)&fmt+sizeof(fmt);
Hier solltest du va_start nehmen; die Argumente muessen nicht
unbedingt im Speicher liegen (in der Tat tun sie das bei den wenigsten
Architekturen).
> l=sprintf(str,"%s: ",prcn);
> (void)vsprintf(str+l,fmt,adr);
> (void)fprintf(stderr,"%s\n",str);
> }
--
Falk
>/* VARARGS1 */
>void errmsg(fmt)
> char* fmt;
>{
> typedef va_list vptype;
> vptype adr;
> char str[320+1];
> int l;
> adr=(vptype)&fmt+sizeof(fmt);
> l=sprintf(str,"%s: ",prcn);
> (void)vsprintf(str+l,fmt,adr);
> (void)fprintf(stderr,"%s\n",str);
Grrrrgh.... vielleicht solltest Du doch mal nachlesen, wie Funktionen
mit variabler Argumentanzahl zu implementieren sind.
>Ergebnis: Der 'vsprintf' verursacht entweder Segfaults oder SIGBUS,
>je nachdem, ob mit '-O3' compiliert wurde oder nicht.
Jau, das geschieht dir recht, würde ich sagen: Undefined Behaviour.
>Gibt es Besonderheiten bei der Parameteruebergabe ?
Niemand garantiert Dir, daß du die Adresse irgendwelchger Argumente
so bzw. überhaupt berechnen kannst; oft haben die gar keine Adresse
(sondern werden in Registern übergeben).
Der Code ist so hochgradig unportabel daß es sich gar nicht lohnt,
darüber zu diskutieren.
Mein Rat: "man stdarg".
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-4596-87 Fax: (+49)-8142-4596-88 Web: www.denx.de
Whom the gods would destroy, they first teach BASIC.
Wenn ich das taete, stiesse ich auf 'stdarg.h'.
Die Verwendung von 'va_start()' im Zusammenhang mit 'stdarg.h' wiederum
erzwingt unter gcc die Verwendung einer Ellipsis, anderenfalls das
schlaue Kerlchen meckert. Vulgo: Dann muesste den ganzen Mist doch
noch auf ANSI-C umstellen.
> >Gibt es Besonderheiten bei der Parameteruebergabe ?
>
> Niemand garantiert Dir, daß du die Adresse irgendwelchger Argumente
> so bzw. überhaupt berechnen kannst; oft haben die gar keine Adresse
> (sondern werden in Registern übergeben).
Nicht wahr ?
Mein Beispielprogramm, das von einem IBM RT stammt, laeuft zu meinem
eigenen Erstaunen auch auf einer POWER2-Maschine, bei der die Parame-
ter normalerweise in Registern uebergeben werden.
> Der Code ist so hochgradig unportabel daß es sich gar nicht lohnt,
> darüber zu diskutieren.
Gerade da wird es doch interessant.
> Mein Rat: "man stdarg".
Das klappt nicht resp. lohnt den Aufwand nicht, s.o..
Was dagegen funktioniert:
[ ... ]
#include <varargs.h>
[ ... ]
void errmsg(fmt,va_alist)
char* fmt;
va_dcl /* expandiert zu 'int va_alist' */
{
typedef va_list vptype;
vptype adr;
char str[320+1];
int l;
/* adr=(vptype)&fmt+sizeof(fmt); */ /* FALSCH */
va_start(adr); /* Funktioniert */
l=sprintf(str,"%s: ",prcn);
(void)vsprintf(str+l,fmt,adr);
(void)fprintf(stderr,"%s\n",str);
}
Nur wuerde ich allerdings schon gerne wissen, was 'va_start' eigent-
lich anderes tut als meine auskommentierte Zeile oben - und das
herauszufinden ist nicht trivial. May the source be with GNU.
PORTABEL, da hast Du recht, ist das freilich nicht.
Danke fuer Deine Hinweise.
> Whom the gods would destroy, they first teach BASIC.
Was wollten die Goetter mit uns tun, als sie uns C schenkten ?
'va_start' tut ja auch nichts anderes als eine Adresse zu berechnen.
Allerdings macht es das offensichtlich besser als ich.
Danke fuer den Hinweis.
> Wolfgang Denk:
>
> > Niemand garantiert Dir, daß du die Adresse irgendwelchger Argumente
> > so bzw. überhaupt berechnen kannst; oft haben die gar keine Adresse
> > (sondern werden in Registern übergeben).
>
> Nicht wahr ?
> Mein Beispielprogramm, das von einem IBM RT stammt, laeuft zu meinem
> eigenen Erstaunen auch auf einer POWER2-Maschine, bei der die Parame-
> ter normalerweise in Registern uebergeben werden.
Das legt die Vermutung nahe, dass die Register memory-mapped sind.
> /* adr=(vptype)&fmt+sizeof(fmt); */ /* FALSCH */
> va_start(adr); /* Funktioniert */
> Nur wuerde ich allerdings schon gerne wissen, was 'va_start' eigent-
> lich anderes tut als meine auskommentierte Zeile oben - und das
> herauszufinden ist nicht trivial. May the source be with GNU.
Mein Vorschlag für die auskommentierte Zeile:
adr=(vptype)(&fmt+1); /* Richtig? */
> PORTABEL, da hast Du recht, ist das freilich nicht.
Meins auch nicht :-)
Gruß. Claus