www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Variable Anzahl an Parameter ohne Mengenparameter


Autor: nowayback (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Tag,

in meinem C-Programm (atxmega128a1) verwende ich folgende Funktion zum 
Versenden von Nachrichten an die Außenwelt:
void send(char* msg, uint8_t len);
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:
void sendC(int anzahl,...)
{
va_list vl;
int i;
char tmp[256]="";

va_start(vl,anzahl);
for (i=0;i<anzahl;i++)
{
strcat(tmp,va_arg(vl,char*));
strcat(tmp,"|"); // "|" ist ein Trennzeichen
}
va_end(vl);
send(tmp);
}

Mit dieser Funktion lassen sich nun sehr einfach Nachrichten mit 
Variablenwerten versenden, zum Beispiel:
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.
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?

Autor: swarner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: eject (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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..

Autor: swarner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zum Glueck war ich mir nicht "ganz sicher" ;)
Anyway, thx, wieder was gelernt.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wie geht das überhaupt mit dem itoa mit nur einem parameter?

> sendC("DEBUG",itoa(var1),itoa(var2),NULL);

Autor: nowayback (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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
void SendC(char * format, ...)
{
  char buffer[256];
  va_list args;

  va_start( args, format );
  vsprintf( buffer, format, args );
  send( buffer );
  va_end( args );
}

Der Aufruf sieht dann völlig gleich aus, wie bei printf oder sprintf
  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.

Autor: nowayback (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: sebastians (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> wie man GCC ohne eigene Kompilierung ;) beibringen könnte, auf den Formatstring 
zu achten

http://en.lmgtfy.com/?q=gcc+check+formatstring

2. Treffer:
http://gcc.gnu.org/onlinedocs/gcc-4.3.2//gcc/Funct...

Sogar mit Beispiel:
extern int
my_printf (void *my_object, const char *my_format, ...)
    __attribute__ ((format (printf, 2, 3)));

Autor: nowayback (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sebastians schrieb:
> http://en.lmgtfy.com/?q=gcc+check+formatstring

Natürlich habe ich gegoogelt, aber meine Keywords hatten leider keinen 
Erfolg.
Ansonsten vielen Dank für den Link!
Diese gerade gefunden Seite erklärt das auch recht gut: 
http://brewforums.qualcomm.com/archive/index.php/t...

Die Funktion habe ich jetzt implementiert und mit verschiedenen Werten 
getestet. Sie funktioniert super und der Compiler bemerkt korrekt 
falsche oder fehlende Parameter.

Hier noch der vollständige Code:
extern void sendC(const char* format, ...) __attribute__ (format (printf,1,2)));
extern void sendC(const char* format, ...)
{
 char buffer[256];
 va_list args;

 va_start(args,format);
 vsprintf(buffer,format,args);
 send(buffer,strlen(buffer)); // Der len-Parameter fehlt im Beispiel oben
 va_end(args);
}

Aufruf wie printf.
Nochmals vielen Dank für Eure Antworten!

Autor: nowayback (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hoppala, falscher Link in der Zwischenablage.
Hier der korrekte Link: 
http://unixwiz.net/techtips/gnu-c-attributes.html#format

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.