sprintf gemischte Datentypen

Hallo zusammen,

ich habe ein paar Datensätze, die ich auf Basis einer Einrichtung erstellen muss.
Diese beinhalten Dezimalzahlen mit unterschiedlichen Trennzeichen, Einheiten, Uhrzeit, Steuerbefehlen, usw. Die Werte haben alle eine feste Länge, die mit Leerzeichen aufgefüllt werden.

Da bietet sich ja sprintf an!
Natürlich habe ich vorher recherchiert und erstelle die Dezimalzahl als zwei getrennte Ganzzahlen.
Und da fängt es schon an:

sprintf(buffer, "% 5d%s%02d% 3s", i, delimeter, d, unit);

Sobald ich die Zahl vor dem Komma (i) und die Nachkommstelle (d) mit einem Trennzeichen versehe, stimmt die Ausgabe nicht mehr. Weder Trennzeichen, noch die Einheit werden ausgegeben.
Setze ich anstelle von der variablen "delimeter" hart einen Punkt oder ein Komma, sind die Nachkommastellen immer 00, obwohl in d definitiv etwas drinsteht.

Funktioniert sprintf() nur vernünftig mit einer Variablen? Wie kann ich komplexere Datensätze bauen, ohne den buffer nach jedem Aufruf zusammenkopieren zu müssen?

Habe etwas Sorge, dass ich mit zahlreichen verschachtelten switch-case und etlichen CopyBufferToBuffer-Funktionen enden werde :confused:

Vielleicht habt Ihr ja eine elegantere Idee, wie ich auf Basis von verschiedenen Einrichtungen, mehrere Werte verketten kann.

char buffer[13];
int i = 123;
int d = 45;
char* delimiter = ",";  // korr
char* unit = "m/s";

sprintf(buffer, "%5d%s%02d %3s", i, delimiter, d, unit); // ergibt buffer = "  123,45 m/s"

Dein Problem ist evtl., dass %s nicht ein char, sondern einen char* erwartet ?

Hi michael_x,

danke für Deine Antwort!

Scheinbar aber nicht, macht keinen Unterschied:

char* del;
if(Delimeter)
  del = ",";
else
  del = ".";
sprintf(weight, "% 5d%s%.2d kg", i, del, d); //  823442 kg

Allerdings funktioniert nichtmal die harte Programmierung:

if(Delimeter)
  sprintf(weight, "% 5d,%.2d kg", i, d); //  823,00 kg
else
  sprintf(weight, "% 5d.%.2d kg", i, d);//  823.00 kg

Wobei die Nachkommastellen definitiv gefüllt sind.

%.2d gibt Nachkommastellen aus, die Du bei int nicht hast --> 0
%02d gibt 2 Stellen mit führender 0 aus, das wolltest Du wohl.

Gruß Tommy

Also bei mir (auf dem PC mit VisualStudio) macht weder das merkwürdige Leerzeichen in "% 5d" noch der merkwürdige Punkt in "%.2d" etwas aus...

(Aber mein eigenes Beispiel geht da natürlich auch, wenn man es korrigert :wink: )

Vermutlich ist der Fehler wie üblich im wesentlicheren Teil, den Variablen-Definitionen.
(Wer die weglässt, muss bei mir auf Welpenschutz hoffen)

@michael_x: IDE 1.6.5 sagt zu #1: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]

So dann ohne Warnung:

  char buffer[13];
  int i = 123;
  int d = 45;
  const char delimiter[] = ",";  // korr
  const char unit[] = "m/s";

  sprintf(buffer, "%5d%s%02d %3s", i, delimiter, d, unit); // ergibt buffer = "  123,45 m/s"

warning: deprecated conversion

Da habt ihr ( agmue und avr-gcc ) ja sowas von Recht. Danke!
(Werconstweglässt nimmt auchintals Datentyp und ist auch sonst sehr schlampig)

VisualStudio c++ hält dafür sprintf für unsicher :wink:

Recht wollte ich nicht haben, nur etwas spielen, bin ja neugierig ::slight_smile:

Dann müßte dies die sichere Variante sein?

  char buffer[13];
  int i = 123;
  int d = 45;
  const char delimiter[] = ",";  // korr
  const char unit[] = "m/s";

  snprintf(buffer, sizeof(buffer), "%5d%s%02d %3s", i, delimiter, d, unit); // ergibt buffer = "  123,45 m/s"

Ja. (Microsoft hat auch noch eine Template Version (sprintfs). )

Zum Topic zurück:

Es gibt übrigens auch das Format "%c",

  bool KommaDelimiter = true;

  char del = KommaDelimiter ? ',' : '.' ;
  
  char buffer[13];
  int i = 123;
  int d = 45;
  const char unit[] = "m/s";

  snprintf(buffer, sizeof(buffer), "%5d%c%02d %3s", i, del, d, unit); // ergibt buffer = "  123,45 m/s"

Die "komischen" Leerzeichen und der Punkt stammen aus der C Doku.

A precision value in the form of a period ('.'), followed by an optional digit string.
' ' (a space): To specify that a blank should be left before a positive number.
printf("% d", 7); # prints ' 7'

Das war auch nur einer von vielen Tests, in der Hoffnung, dass die Varianten auf dem Arduino implementiert werden.

Habe nun alles nochmal gelöscht und von vorne begonnen und siehe da! Es klappt :o

  uint16_t i = random(MinIntegerPlaces,MaxIntegerPlaces);
  uint16_t d = random(MinDecimalPlaces,MaxDecimalPlaces);
  const char unit[] = "kg";
  char del[] = ".";
  if(Delimiter)
    del[0] = ',';
  char weight[60];
  sprintf(weight, "%5d%s%02d %s", i, del, d, unit);
  Serial.print(weight);
  // 347.83 kg

Keine Ahnung ob ich dort nun irgendwie ein Sonderzeichen rein gecopy-&-pasted habe oder einfach blind gewesen bin...

Auch komplexere Kombinationen mit Brutto und Netto Werten funktionieren jetzt:

sprintf(weight, "% 10d%s%.2d %s% 10d%s%.2d %s% 10d%s%.2d %s", i, del, d, unit, i_net, del, d_net, unit, i-i_net, del, d-d_net, unit);
   //        184.80 kg       183.80 kg         1.00 kg

Vielen Dank Euch allen!

Die "komischen" Leerzeichen und der Punkt stammen aus der C Doku

roten Kopf krieg Doku lesen ist nie verkehrt.
Ich habe das nun schon hunderte von Jahren so geschrieben:

  sprintf (buffer, " %d", 7); // ergibt " 7" mit führendem Leerzeichen

Danke.

Habe nun alles nochmal gelöscht und von vorne begonnen und siehe da! Es klappt

Na prima! Ende gut, alles gut.