Guten Tag,
in meinem C-Programm (atxmega128a1) verwende ich folgende Funktion zum
Versenden von Nachrichten an die Außenwelt:
1
voidsend(char*msg,uint8_tlen);
Da diese Nachrichten auch öfter Variablenwerte beinhalten, die
normalerweise erst umständlich mittels strcat in ein Zwischenpuffer
geschrieben werden müssten bevor man die Nachricht mittels send
versenden kann, will ich eine Funktion schreiben, die beliebig viele
Parameter miteinander verknüpft und anschließend absendet. Dafür habe
ich bereits folgende Funktion geschrieben:
1
voidsendC(intanzahl,...)
2
{
3
va_listvl;
4
inti;
5
chartmp[256]="";
6
7
va_start(vl,anzahl);
8
for(i=0;i<anzahl;i++)
9
{
10
strcat(tmp,va_arg(vl,char*));
11
strcat(tmp,"|");// "|" ist ein Trennzeichen
12
}
13
va_end(vl);
14
send(tmp);
15
}
Mit dieser Funktion lassen sich nun sehr einfach Nachrichten mit
Variablenwerten versenden, zum Beispiel:
1
sendC(3,"DEBUG",itoa(var1),itoa(var2));
Allerdings muss nun ständig an erster Stelle übergeben werden, wie viele
char*-Parameter der Funktion übergeben werden.
Im Internet habe ich auch die Variante gefunden, dass der letzte
Parameter immer NULL ist und anhand von diesem das Ende erkannt werden
kann, also z.B.
1
sendC("DEBUG",itoa(var1),itoa(var2),NULL);
Natürlich benötigt auch diese Variante immer einen weiteren Parameter.
Gibt es auch eine Methode, ohne weitere Parameter auszukommen, wie es
zum Beispiel sprintf macht? Oder erkennt sprintf selbst die Anzahl der
Parameter anhand der angeforderten Parameter im Format-String und eine
Reduktion der Funktion auf die wesentlichen char*-Parameter ist nicht
möglich?
Wie macht Ihr das in euren Programmen?
Hi,
Ich bin mir ziemlich sicher, dass Du den letzten Parameter einfach
weglassen kannst. Der wird automatisch auf NULL gesetzt (ist ja nicht
vorhanden).
Damit kannst Du das Ende Deiner Parameterliste leicht erkennen.
Gruß
Sascha Warner
nowayback schrieb:> Natürlich benötigt auch diese Variante immer einen weiteren Parameter.> Gibt es auch eine Methode, ohne weitere Parameter auszukommen
Nope
> wie es> zum Beispiel sprintf macht? Oder erkennt sprintf selbst die Anzahl der> Parameter anhand der angeforderten Parameter im Format-String
exakt
Genau das ist auch der Grund, warum man beim Format String peinlich
genau sein muss und man dem gcc eine Überprüfung des Format-Strings mit
den Argumenten beim Aufruf spendiert hat. Geht da was schief, sind die
Auswirkungen oft verheerend.
> Wie macht Ihr das in euren Programmen?
variable Argument-Listen nach Möglichkeit vermeiden.
swarner schrieb:> Ich bin mir ziemlich sicher, dass Du den letzten Parameter einfach> weglassen kannst. Der wird automatisch auf NULL gesetzt (ist ja nicht> vorhanden).
nein, das sind werte die auf de Stack liege, wer sollte denn dort ein
NULL hinlegen? man bekommt beim lesen einfach die DAten die dort zu
letzt standen. Entweder schafft man es geschickt über ein Makro das am
ende immer eine NULL steht oder man muss die länge mitgeben.
Printf macht es anhand des Format Strings, schreibt doch mal
printf("%s%d%s%d");
dann sieht du was er macht.
jede woche kommt wieder einer der ned suchen kann und stellt die gleiche
frage... anstatt mal sinvolle ideen zu haben will man immer nur alles
mögliche haben.
zuerst losfrickeln und sich dann wundern wenn nix passend
funktioniert...
schade sowas
echt jetzt..
Vielen Dank für Eure Antworten.
@swarner: Habe jetzt zwar testweise auf NULL am Ende überprüft..aber da
kommt tatsächlich keines ;)
@Peter: Das mit dem Makro hört sich vielversprechend an, da werde ich
mal ansetzen. Den itoa-Befehl habe ich übrigens nur exemplarisch
hingeschrieben, der echte itoa-Befehl benötigt natürlich drei Parameter.
Karl heinz Buchegger schrieb:> variable Argument-Listen nach Möglichkeit vermeiden.
Aber wenn es nicht anders geht, dann nach Möglichkeit einen bereits
bekannten Mechanismus benutzen und keinen eigenen erfinden.
Dazu sind manchmal die Funktionen aus der printf-Familie hilfreich, die
es auch in einer Form gibt, dass man sie in eigenen variadischen
Funktion benutzen kann.
zb vsprintf als variadische Form vom sprintf
1
voidSendC(char*format,...)
2
{
3
charbuffer[256];
4
va_listargs;
5
6
va_start(args,format);
7
vsprintf(buffer,format,args);
8
send(buffer);
9
va_end(args);
10
}
Der Aufruf sieht dann völlig gleich aus, wie bei printf oder sprintf
1
SendC("DEBUG|%d|%d",var1,var2);
mit allen Vor und Nachteilen (vor allen Dingen Nachteilen). Wenn man
jetzt den gcc noch dazu bringen könnte, den Formatstring im Aufruf
ähnlich wie bei printf zu checken, wäre das (fast) perfekt.
Jep, so etwas wäre natürlich die perfekte Lösung! Dann könnte ich auch
gleich im Formatstring bei Integern meine gewünschte Anzahl an Ziffern
angeben. Hast du Ansätze, wie man GCC ohne eigene Kompilierung ;)
beibringen könnte, auf den Formatstring zu achten?
nowayback schrieb:> angeben. Hast du Ansätze, wie man GCC ohne eigene Kompilierung ;)> beibringen könnte, auf den Formatstring zu achten?
Nein. Leider.
Ich weiß nicht wie das funktioniert.
Ich würde mir aber mal die stdio.h genauer ansehen und dort die Funktion
printf suchen. Mit ein wenig Glück steht dort eine
Funktionsattributierung, die dieses Verhalten für den gcc einschaltet.
Steht dort beim Protoyp nichts dabei, dann ist dieser Formatstring-Check
direkt hadcoded in den gcc eingebaut worden.