Forum: Mikrocontroller und Digitale Elektronik sprintf Anzahl der Stellen über define festlegen


von Anton G. (antong)


Lesenswert?

Hallo,
ich versuche beim Atmega über sprintf die Ausgabe einer Zahl zu 
formatieren.

Folgendes klappt:
sprintf(puffer,"%3u\t",daten);

Die Zahl die in "daten" steht, wird immer 3 stellig ausgegeben.

Ich möchte aber nun statt der %3u eine Zahl über ein #define übergeben.

Also in einer .h Datei:
#define ANZAHL 3 // Anzahl der Zeichen die ausgegeben werden sollen

und dann in meiner .c Datei
sprintf(puffer,"%ANZAHLu\t",daten);

Das funktioniert leider nicht. Was mache ich falsch?

Gruß antong

von asyxdcvgh (Gast)


Lesenswert?

Der Präprozessor interessiert sich nicht für Stringkonstanten, ergo er 
ersetzt dort enthaltene Makros nicht.

nicht schön aber selten:
#define ANZAHL "6"
sprintf(puffer,"%"ANZAHL"u\t",daten);
(Funktioniert weil mehrere nebeneinanderliegende Strings wie ein 
einzelnder behandelt werden)

alternativ gibt es iirc auch eine Möglichkeit sprintf die Länge als 2. 
Parameter zu übergeben, hab aber die Syntax dazu nicht im Kopf.

von Falk B. (falk)


Lesenswert?

@  Anton G. (antong)

>Das funktioniert leider nicht. Was mache ich falsch?

Normale Define funktionieren nicht in Strings. Da gibt es aber eine 
Lösung, die mir aber im Moment nicht einfällt, stand in einem C-Buch.

http://stackoverflow.com/questions/1079020/can-you-expand-defines-into-string-literals

Das ist aber nur ein HACK, es gibt einen offiellen Weg, ich glaube 
irgendwas mit ##

von Karl H. (kbuchegg)


Lesenswert?

asyxdcvgh schrieb:

> alternativ gibt es iirc auch eine Möglichkeit sprintf die Länge als 2.
> Parameter zu übergeben, hab aber die Syntax dazu nicht im Kopf.

Da war was, ja.

Früher hat man das eben so gemacht, dass man sich zuerst den 
Formatstring zusammengebaut hat

   sprintf( FormatString, "%%%du\t", ANZAHL );

und dann eben diesen anstelle eines fixen Strings benutzt hat

   sprintf( puffer, FormatString, daten);


Aber wie das mit der Direktangabe im Formatstring geht, weiß ich auch 
nicht auswendig.

Ah. weiß wieder. Der * macht das

   sprintf(puffer, "%*u\t", ANZAHL, daten);

von asyxdcvgh (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ah. weiß wieder. Der * macht das
>
>    sprintf(puffer, "%*u\t", ANZAHL, daten);
Ah genau, das hatte ich im Hinterkopf, war mir aber nicht sicher...

von Anton G. (antong)


Lesenswert?

Hallo,
vielen Dank erst mal für die ganzen Antworten.
Leider funktioniert das aber bei mir immer noch nicht ganz.

Folgendes funktioniert:
1
...
2
uint8_t puffer[20];
3
uint8_t value = 123;
4
...
5
sprintf( puffer, "Zählerstand: %3u",value);
6
USART1_String_senden(puffer);
7
...

Dieses funktioniert aber nicht:
1
#define ANZAHL 3
2
...
3
uint8_t puffer[20];
4
uint8_t value = 123;
5
...
6
sprintf( puffer, "Zählerstand: %*u", ANZAHL, value);
7
USART1_String_senden(puffer);
8
...

Auch wenn ich statt ANZAHL direkt eine Zahl einsetze, erscheint nichts 
über die UART. Die Zahl 123 fehlt einfach.

@asyxdcvgh(Gast)
Deine Lösung funktioniert auch.Sieht allerdings wirklich ein wenig 
komisch aus.
1
...
2
#define ANZAHL "6"
3
...
4
sprintf( puffer, "Zählerstand: %"ANZAHL"u", value);
5
...

Ich habe auch schon im Internet nach der "%*u" Methode gesucht. Ist aber 
schwierig zu finden, da man nach dem Sternchen schlecht suchen kann.

Falls noch jemand eine Idee hat warum das nicht funktioniert, dann würde 
ich mich freuen. Ansonsten würde ich die Alternative von 
asyxdcvgh(Gast)erst einmal nehmen.

Vielen Dank euch allen.

Gruß Antong

von Klaus W. (mfgkw)


Lesenswert?

Anton G. schrieb:
> Falls noch jemand eine Idee hat warum das nicht funktioniert, dann würde
> ich mich freuen.

Das (s)printf() in der avr-libc unterstützt nicht den ANSI-Standard 
komplett.
Siehe: 
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1

Da steht:
"Notes: ... The variable width or precision field (an asterisk * symbol) 
is not realized and will to abort the output. "

von Anton G. (antong)


Lesenswert?

Schade. Würde etwas schöner ausschauen. Aber egal, hauptsache es 
funktioniert.
Vielen Dank.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ah. weiß wieder. Der * macht das
>
>    sprintf(puffer, "%*u\t", ANZAHL, daten);

Stimmt, ist aber eher umständlich, weil dann die Konstante einzeln an 
die Funktion übergeben wird - außer der Compiler optimiert das raus. Und 
es geht nur, wenn der Compiler das auch unterstützt.

Der einfachste Ansatz ist aber der hier:
1
sprintf(puffer, "%" #ANZAHL "u\t", daten);

von Klaus W. (mfgkw)


Lesenswert?

Markus W. schrieb:
> sprintf(puffer, "%" #ANZAHL "u\t", daten);

das mit dem # geht aber nur innerhalb eines Makros.

von Achim M. (minifloat)


Lesenswert?


von Klaus W. (mfgkw)


Lesenswert?

Der geht auch nur in einem Makro.

von Vlad T. (vlad_tepesch)


Lesenswert?

was ist denn so schlimm daran
1
#define ANZAHL "6" 
2
sprintf(puffer, "%" ANZAHL "u\t", daten);
zu schreiben?

ansonsten ginge glaub ich das:
1
#define STRINGIFY_SUB(str) #str
2
#define STRINGIFY(str) STRINGIFY_SUB(str)
3
4
#define ANZAHL 6
5
6
sprintf(puffer, "%" STRINGIFY(ANZAHL) "u\t", daten);
bin mir aber nicht ganz sicher. dieser Teil der Präprozessor-Magie ist 
so hinrverknotend

edit:
scheint zu stimmen, hier sieht es ähnlich aus:
http://sunsite.ualberta.ca/Documentation/Gnu/gcc-3.0.2/html_chapter/cpp_3.html#SEC17

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Klaus Wachtler schrieb:
> Markus W. schrieb:
>> sprintf(puffer, "%" #ANZAHL "u\t", daten);
>
> das mit dem # geht aber nur innerhalb eines Makros.

Hoppla, ich glaub du hast Recht. :-)
Dann eben so:
1
#define ANZAHL_S #ANZAHL
2
sprintf(puffer, "%" ANZAHL_S "u\t", daten);

von Prachz Kerl (Gast)


Lesenswert?

Wenn man sprintf benutzen muss sollte man gleich den Strick bestellen. 
Mit dieser Libraryfunktion ist gleich der halbe Codespeicher belegt.

von Anton G. (antong)


Lesenswert?

Hallo,
so ich habe nun einiges getestet von den Antworten oben.

Die Variante von Markus W. funktioniert bei mir leider nicht. Da 
bemängelt er die # in der C Datei.
>
1
#define ANZAHL_S #ANZAHL
2
sprintf(puffer, "%" ANZAHL_S "u\t", daten);
3
>

Zwei Varianten funktionieren bei mir.
Die erste Variante von asyxdcvgh (Gast)
>
1
> ...
2
> #define ANZAHL "6"
3
> ...
4
> sprintf( puffer, "Zählerstand: %"ANZAHL"u", value);
5
> ...
6
>
Hat aber den Nachteil, dass ich die ANZAHL später auch noch mal als Zahl 
benötige und hier nur einen String in der ANZAHL habe.

Das einzige was bei mir wirklich funktioniert, ist die Variante von Vlad 
Tepesch.
>
1
> #define STRINGIFY_SUB(str) #str
2
> #define STRINGIFY(str) STRINGIFY_SUB(str)
3
> 
4
> #define ANZAHL 6
5
> 
6
> sprintf(puffer, "%" STRINGIFY(ANZAHL) "u\t", daten);
7
> 
8
>
Hier kann ich die ANZAHL später auch noch als ganz normal Zahl nutzen.

Ich tue mich immer sehr schwer mit solchen Makros. Wenn ich das Richtig 
verstehe, funktioniert das so(bitte korrigiert mich):

Der Preprozessor ersetzt den Text
'STRINGIFY(ANZAHL)' zuerst in 'STRINGIFY_SUB(ANZAHL)' und dann noch mal 
'STRINGIFY_SUB(ANZAHL)' in "6". Die # macht ja praktisch einen String 
daraus.
Warum muss das so kompliziert. Warum geht nicht einfach:
1
 #define STRINGIFY(str) #str
2
 
3
 #define ANZAHL 6
4
 
5
 sprintf(puffer, "%" STRINGIFY(ANZAHL) "u\t", daten);
Diese gekürzte Version funktioniert nicht. Verstehen tue ich das 
allerdings nicht, da im Endeffekt doch das gleiche dabei rauskommen 
müsste, oder nicht?

@Prachz Kerl
Ist schon klar, dass die Funktion Rechenzeit und Speicher frisst. Soll 
im Moment aber erst mal trotzdem so gemacht werden.

Viele Grüße
antong

von Stefan E. (sternst)


Lesenswert?

Anton G. schrieb:
> Diese gekürzte Version funktioniert nicht. Verstehen tue ich das
> allerdings nicht, da im Endeffekt doch das gleiche dabei rauskommen
> müsste, oder nicht?

Das "String-machen" muss einfach etwas verzögert werden, damit vorher 
das ANZAHL durch 6 ersetzt wird:

STRINGIFY(ANZAHL) -> STRINGIFY_SUB(6) -> "6"

Deine gekürzte Variante wäre:

STRINGIFY(ANZAHL) -> "ANZAHL"

Und da wird dann ANZAHL nicht mehr durch 6 ersetzt, weil ja innerhalb 
von Strings nichts ersetzt wird.

von Anton G. (antong)


Lesenswert?

Danke Stefan Ernst.

Also muss ich mein Verständnis oben korrigieren nach

'STRINGIFY(ANZAHL)' zuerst in 'STRINGIFY_SUB(6)' und dann noch mal
'STRINGIFY_SUB(6)' in "6".

Dann ist das auch gar nicht mehr so unlogisch.
Danke an Allen. Habt mir sehr geholfen.
Gruß antong

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.