Argumentliste- Problem
-
Hi Forumsmitglieder,
ausnahmsweise bewerfe ich euch nicht mit einem Nixi, der Code tut, was er soll. Allerdings bin ich nicht ganz glücklich
, warum es nur so dödelig geht:
// *********************************************************** // ********** Integer bearbeiten ***************************** // *********************************************************** char EditIntAt(char x, char y, unsigned int * value, int min, int max, char far * format, ...) { va_list argzeiger; char length, backkey = 0; char far * editstring = malloc(10); unsigned int wert; if (editstring) { va_start(argzeiger, format); length = vsprintf(editstring, format, argzeiger); va_end(argzeiger); do { backkey = EditStringAt(x,y,editstring, "0123456789"); sscanf( editstring, "%d", &wert ); } while ((wert > max) && (wert < min)); free(editstring); if (backkey == 13) *value = wert; } return backkey; // *********************************************************** // ********** Aufruf aus Main ******************************** // *********************************************************** void main(void) { unsigned int test; test = EditIntAt(0, 0, &test, 1, 8888, "%-4d", test); }
Mich stört, daß ich den Formatstring bereits von "oben" aus mitreichen muß, weil alle Versuche, innerhalb von EditIntAt() den Formatstring aus mitgereichten Parametern zu generieren und daraus eine va_list an vsprintf() weiterzureichen, kläglich gescheitert sind
. Ergebnisse zwischen grobem Unsinn
und Totalabstürzen des Targets
waren die Folge.
Weiter unschön, daß ich "test" zweifach durchreichen muß, einmal als Adresse, einmal als Value.
Ersetze ich die Weitergabe von Wert "test" durch eine Referenz im ...- Teil, packt das vsprintf() mit 'ner Warning nicht, und wahrlich, das Compilat stürzt ab.Liebe Leute, habt ihr keine Idee, wie das eleganter geht
Ich weiß, man kann das auch so durchfrickeln, aber ich hab' massiv das Gefühl, daß die C- Welt schöner sein müßte
, aber ich seh' grad nicht, wie!
-
was soll denn die funktion machen?
du könntest aus den ganzen parametern eine struct machen und der funktion einen pointer darauf geben...
-
Naja bleicher Hund
,
machen sollte sie, daß ein String im Rahmen der zulässigen (unsigned int, min, max) Möglichkeiten ausgegeben und rückgelesen wird.
Mein Traumaufruf wäre
returnkey = EditIntAt(char x, char y, unsigned int * value, int min, int max, char far * format)
Aber das krieg' ich irgendwie nicht hin
, an dem Argumentlistenzeugs klemmt's immer irgendwie, nichtmal "format" krieg' ich so zu fassen, kommt nur Speichermüll raus.
Hilft das zur Präzisierung
-
pointercrash() schrieb:
machen sollte sie, daß ein String im Rahmen der zulässigen (unsigned int, min, max) Möglichkeiten ausgegeben und rückgelesen wird.
also du willst einen string, in dem ein 'int' wert ist, ausgeben und den 'int' wieder zurückbekommen aber der 'int' darf nur in einem gewissen bereich sein?
wozu dann die va_list?
versteh' ich nicht. ich glaub' du musste es noch genauer erklären...
-
pale dog schrieb:
also du willst einen string, in dem ein 'int' wert ist, ausgeben und den 'int' wieder zurückbekommen aber der 'int' darf nur in einem gewissen bereich sein?
wozu dann die va_list?
versteh' ich nicht. ich glaub' du musste es noch genauer erklären...
Ich hab's auch nicht verstanden, aber es scheint so, daß vsprintf() auf einem Argumentzeiger besteht
. Versuche ich ohne va_list auszukommen, sähe das z.B. so aus:
// *********************************************************** // ********** Integer bearbeiten ***************************** // *********************************************************** char EditIntAt(char x, char y,unsigned int * value, int min, int max, char space) { char length, backkey = 0; char far * format = malloc(5); char far * editstring = malloc(10); unsigned int wert; if (format) { format = "%- d"; format[2]= space + '0'; wert = *value; if (editstring) { length = vsprintf(editstring, format, wert); // [Warning(ccom):edit.c,line 160] mismatch prototyped parameter type do { backkey = EditStringAt(x,y,editstring, "0123456789"); sscanf( editstring, "%d", &wert ); } while ((wert > max) && (wert < min)); if (backkey == 13) *value = wert; free(editstring); } free(format); } return backkey; } // Aufruf: test = EditIntAt(0, 0, &test, 1, 8888, 4);
... und das wird an bezeichneter Stelle moniert. Ein
length = printf(format, wert);
hingegen wird ohne Murren korrekt verarbeitet. Die printf()- Ausgabe muß ich jedoch ins Nirvana schicken, weil der Standardkanal auf meine Debugger- Schnittstelle zeigt
und wenn ich das ändere, kriegen wiederum andere Projekte Probleme mit den geänderten Libs.
Tja, aber die Umleitung über einen Ausgabebuffer verlangt va_list - jetzt klarer, wo das Problem liegt
-
vsprintf() brauchst du nur, wenn du die Daten der variablen Argumentliste ausgeben willst. Für deine Zwecke reicht ein normales
sprintf(editstring,format,wert);
aus.
-
CStoll schrieb:
Für deine Zwecke reicht ein normales
sprintf(editstring,format,wert);
aus.Eben nicht, da format zwingend
const char * format
haben muß, deswegen führt das Compilat die Zeile
format[2] = space + '0';
nicht aus und ich habe so nicht die Möglichkeit, das Ausgabeformat zu beeinflussen. Und tatsächlich - es geht leider wirklich nicht
.
Noch 'ne Idee??
-
pointercrash() schrieb:
Eben nicht, da format zwingend
const char * format
haben muß,
Falsch. Du kannst nicht-const-Dinge an const-Parameter übergeben. Nur andersrum geht es nicht. Leg doch einfach ein hinreichend großes char-Array für deinen Formatstring an.
-
Kannst du DAS Problem mal genauer beschreiben? Du kannst doch problemlos einen normalen 'char*' an eine Funktion übergeben, die einen 'const char*' erwartet (umgekehrt geht es glücklicherweise nicht so einfach). Also was hat dein Compiler daran auszusetzen?
(btw, vsprintf() erwartet genauso einen const char* als Formatangabe ;))
-
CStoll schrieb:
Also was hat dein Compiler daran auszusetzen?
Er legt format automatisch im ROM an (µC), wo Schreibzugriffe zur runtime nicht klappen.
CStoll schrieb:
(btw, vsprintf() erwartet genauso einen const char* als Formatangabe ;))
Richtig, da ist der Compiler in dieser Hinsicht freizügiger (format landet im RAM), besteht aber auf der Argumentliste
.
-
pointercrash() schrieb:
Er legt format automatisch im ROM an (µC), wo Schreibzugriffe zur runtime nicht klappen.
format ist bei dir nur ein Zeiger, der landet sicher nicht im ROM, weil er auf dem Stack liegt. Allenfalls landet das Literal, auf das du ihn zeigen lässt, dort. Darum sollst du ja auch ein Array benutzen.
-
Nochmal langsam: Worüber genau beschwert sich der Compiler bei so einem Quelltext (der Kern deines Programmes - etwas vereinfacht):
int wert=4711; char format[]="%- d",output[10]; format[2]='1'; sprintf(output,format,wert);
-
CStoll schrieb:
Nochmal langsam: Worüber genau beschwert sich der Compiler bei so einem Quelltext
Er beschwert sich nicht, format zeigt nur einfach auf's ROM und ich kann den Space nicht mit der gewünschten Ausgabebreite überschreiben, ich probier's mal mit 'nem Array ...
-
pointercrash() schrieb:
CStoll schrieb:
Nochmal langsam: Worüber genau beschwert sich der Compiler bei so einem Quelltext
Er beschwert sich nicht, format zeigt nur einfach auf's ROM und ich kann den Space nicht mit der gewünschten Ausgabebreite überschreiben, ich probier's mal mit 'nem Array ...
Wenn du den Formatstring als String-Literal angibst, ja (aber das hat nichts mit sprintf() zu tun). Deswegen mußt du die Daten auch in ein eigenes Array packen.
*genau hinsieht* Und so langsam erkenne ich auch den Fehler in deinem obigen Programm:
char far * format = malloc(5); char far * editstring = malloc(10); unsigned int wert; if (format) { format = "%- d"; format[2]= space + '0'; ... free(format); }
Zeile 7 kopiert NICHT den Inhalt des String-Literals in den Speicherbereich, den du in Zeile 1 angefordert hast, sondern biegt den Zeiger 'format' um auf die Adresse dieses Literals (im ROM). Das bewirkt einerseits ein Speicherleck (bei der Zuweisung verlierst du die Adresse des 5-Byte-Blockes aus Zeile 1) und andererseits Zugriffsfehler in Zeile 8 (das Literal liegt im ROM) und 10 (der Zeiger zeigt auf nichts, was von malloc() bereitgestellt wurde). Wenn du die Stringdaten kopieren willst, mußt du dazu strcpy() verwenden.
-
MFK schrieb:
format ist bei dir nur ein Zeiger, der landet sicher nicht im ROM, weil er auf dem Stack liegt. Allenfalls landet das Literal, auf das du ihn zeigen lässt, dort. Darum sollst du ja auch ein Array benutzen.
Jaaaa, war schon so gemeint, daß format ins ROM zeigt und nicht dort liegt
Soo, einchar format[5] = "%- d"
läßt format auf den Frame zeigen, damit klappt auch das Überschreiben des spaces mit der Ausgabebreite, das vergessene free(format) ist erwiesenermaßen ungesund
, aber jetzt klappt alles.
Meine Herren, ich bedanke mich für Ihre Beihilfe!!!
-
CStoll schrieb:
Zeile 7 kopiert NICHT den Inhalt des String-Literals in den Speicherbereich, den du in Zeile 1 angefordert hast, sondern biegt den Zeiger 'format' um auf die Adresse dieses Literals (im ROM).
Stimmt, das war ein böser Fehler, danke für den Hinweis, das könnte auch eine andere Sache erklären (ganz woanders).
Danke nochmals!!