Go Down

Topic: erledigt: Formatierung mit sprintf, falscher Platzhalter? (Read 2275 times) previous topic - next topic

1N4007

Jan 04, 2014, 08:30 pm Last Edit: Jan 05, 2014, 12:20 am by 1N4007 Reason: 1
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:
Code: [Select]
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:

Code: [Select]

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

jurs


Welcher Platzhalter ist hier richtig


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


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.

Serenifly

#2
Jan 04, 2014, 08:46 pm Last Edit: Jan 04, 2014, 10:16 pm by Serenifly Reason: 1
%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:
Code: [Select]
char* createTimestamp(void)
{
   char doWeek[3];
   static char clockString[24];

  ....

   return clockString;
}


Und sowas machen:
Code: [Select]

char* str = createTimestamp()

oder:
Code: [Select]

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.

1N4007

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

Serenifly

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):

Code: [Select]
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

1N4007

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

Go Up