erledigt: Formatierung mit sprintf, falscher Platzhalter?

Hallo Forum,

ich möchte eine Routine zum erzeugen eines timestamps schreiben, Dieser sprinf ist ja wirklich mächtig, für mich irgendwie zu mächtig.

Dieser Aufruf funktioniert einwandfrei:

sprintf(clockString, " %02u.%02u.20%02u %02u:%02u:%02u", dateTime.getDay(), dateTime.getMonth(), dateTime.getYear(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond());

Sobald ich allerdings noch einen Wochentag hinzufüge, stoppt die Serielle Ausgabe komplett:

String doWeek = "";
String timestamp = "";


void printClockSerial(void)
{
  createTimestamp();
  Serial.println(timestamp);

}

void createTimestamp(void){

  timestamp = "";

  int dowe = dateTime.getWeekday();
  switch (dowe) {
  case 0:    // 0 =  Montag
    doWeek = "Mo";
    break;    
  case 1:    // 1 = Dienstag
    doWeek = "Di";
    break;    
  case 2:    // 2 = Mittwoch
    doWeek = "Mi";
    break;    
  case 3:    // 3 = Donnerstag
    doWeek = "Do";
    break;    
  case 4:    // 4 = Freitag
    doWeek = "Fr";
    break;    
  case 5:    // 5 = Samstag
    doWeek = "Sa";
    break;    
  case 6:    // 6 = Sonntag
    doWeek = "So";
    break;    
  } 

  char clockString[24];

  sprintf(clockString, "%s %02u.%02u.20%02u %02u:%02u:%02u", doWeek, dateTime.getDay(), dateTime.getMonth(), dateTime.getYear(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond());

//  timestamp += String(doWeek); // This works fine
  timestamp += String(clockString); //This works fine
}

Welcher Platzhalter ist hier richtig oder bin ich völlig auf dem Holzweg?

Danke Lars

1N4007: Welcher Platzhalter ist hier richtig

Falsche Frage. Die richtige Frage wäre: "Welchen Datentyp müßte ich verwenden?"

1N4007: oder bin ich völlig auf dem Holzweg?

Ja.

Der Platzhalter "%s" im Formatierungsstring ist schon richtig, aber der dient zur Formatierung von nullterminierten C-Strings und NICHT zur Formatierung von String-Objekten.

String-Objekte sind kompatibel zu String-Objekten.

C-Strings sind kompatibel zur AVR libc library, zu der beispielsweise die sprintf-Funktion gehört.

%d reicht normalerweise. Aber daran liegt es nicht

Bleib da mal bei C Strings statt den String Objekten. Das ist absolut unnötig. Da wird nur Speicher verschwendet so wie du das machst.

Du definierst in der Funktion am Anfang ein kleines Puffer Array: char doWeek[3];

Dann machst du das zum füllen: strcpy(doWeek, "Mo");

http://www.cplusplus.com/reference/cstring/strcpy/?kw=strcpy

Dieses Array kannst du dann wie du es hast in sprintf() mit %s ansprechen

Und wozu soll das sein: String timestamp = "";

Unsinn. Wenn du den String außerhalb brauchst, dann definiere char clockString[24] innerhalb der Funktion als "static". Dann behält das den Speicher auch wenn du die Funktion verlässt. Du kannst dann die Funktion einen Pointer auf das Array zurückgeben lassen:

char* createTimestamp(void)
{ 
    char doWeek[3];
    static char clockString[24];

   ....

    return clockString;
}

Und sowas machen:

char* str = createTimestamp()

oder:

Serial.println(createTimestamp());

Da musst du dir darüber im Klaren sein, dass du keine Zeiger auf lokale nicht-static Variablen zurückgeben kannst. Die andere Möglichkeit (und was die ganzen C Funktionen machen) ist den Puffer außerhalb zu definieren und einen Zeiger auf den Puffer als Parameter zu übergeben. So wie sprintf selbst einen Zeiger auf dein leeres String Array möchte.

Auch daran denken, dass clockString mindestens Platz für den String + 1 haben muss. Da gibt es auch snprintf() das da ein klein wenig sicherer ist, da die Puffer Größer übergeben wird: http://www.cplusplus.com/reference/cstdio/snprintf/ Hat aber auch den Nachteil, dass der String dann glaube ich nicht korrekt terminiert ist wenn das Ende des Puffers vorzeitig erreicht wird. Aber immerhin schreibt er nicht drüber.

Vielen Dank für die superschnellen Antworten,

@ jurs, ja ich sehe der Holzweg ist sehr steinig ;-)

@ Serenifly, danke für die sehr genaue Fehler bzw. Lösungsbeschreibung, funktioniert einwandfrei.

Schönes Wochenende Lars

Was übrigens noch kürzer geht, ist wenn du deine Wochentage in einem Array aus Strings abspeicherst (was in C zwei-dimensionale Arrays auf char sind):

char days[][3] = { "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So" };

Dann kommst du über den Index an die Tage. days[1] ist z.B. "Di". Du kannst dann einfach an sprintf() day[dateTime.getWeekday()] übergeben

Wow,

sehr schlank (ca: 100 Bytes kleiner) und übersichtlicher. So langsam sehe ich die Vorteile von arrays.

Kleine Korrektur, die Variable in snprintf hießt dann:

days[dateTime.getWeekday()] nicht day[…].

Vielen Dank
Lars