15    Zeitroutinen (time.h)

In diesem Kapitel geht es um Funktionen, mit denen Sie die Computeruhr und das lokale Datum abfragen können. Stellen sie sich vor, Sie benötigen in Ihrem Programm eine Funktion, die genau eine Sekunde lang wartet. Sie sind jetzt wahrscheinlich so weit in der Programmierung fortgeschritten, dass Sie sofort erkennen, dass Sie hierzu keine for-Schleife verwenden können, die schlicht bis zu einem bestimmten Wert hochzählt (z. B. bis 1.000.000.000). Natürlich wissen Sie inzwischen auch, dass es verschiedene schnelle Prozessoren gibt und dass z. B. Ihr Gaming-PC schneller zählt als Ihr betagtes Notebook. Kurz: Es muss speziell für präzise Warteschleifen eine andere Lösung her, und diese Lösung ist die Verwendung von time.h. Diese Standardbibliothek, die Sie mit

#include <time.h>

in Ihr Projekt einbinden können, enthält sehr viele plattformübergreifende Funktionen für den Umgang mit der Computeruhr. Einige nützliche Funktionen der Standardbibliothek time.h sollen nun behandelt werden.

15.1    Die Funktion clock()

Wir wollen nun relativ einfach beginnen und erst einmal das »Einstiegsproblem« dieses Kapitels lösen. Ihr Programm soll also genau zehn Sekunden lang warten und sich danach beenden. Hierzu müssen Sie erst einmal die Computeruhr dahingehend abfragen, wie lange Ihr Programm schon läuft. Diese Information liefert die Funktion clock():

#include <time.h>
unsigned long int cock();

clock() liefert die aktuelle Laufzeit Ihres Programms in Millisekunden zurück, und zwar gemessen ab dem Zeitpunkt, ab dem das Programm zum ersten Mal den Startup-Code ausführt. Eine Ausnahme ist der Raspberry Pi, denn dort wird die Laufzeit in Mikrosekunden zurückgegeben, und der Rückgabetyp ist ein unsigned long long int von einer 64-Bit-Breite.

Um jetzt eine bestimmte Zeit lang warten zu können, nützt Ihnen natürlich die aktuelle Programmlaufzeit allein nicht viel. Sie benötigen also eine separate Funktion, die wir hier einfach delay() nennen. delay() soll eine Variable vom Typ unsigned long int entgegennehmen, die in dieser Variablen angegebene Zeit in Millisekunden warten und anschließend kommentarlos zurückkehren. Schauen wir uns nun die Funktion delay() im Detail an:

01  void delay(unsigned long int millis) {
02 unsigned long int now=clock(); // Zeit am Einsprungspunkt
03 while ((clock()-now)<millis) { } // Warteschleife
04 }

In Zeile (01) wird die Funktion definiert. Diese erhält die zu wartende Zeit in Millisekunden in der Variablen millis. In Zeile (02) wird nun erst einmal die aktuelle Programmlaufzeit festgestellt. Dies ist wichtig, weil Sie ja die Funktion auch aufrufen können, nachdem Ihr Programm schon eine unbestimmte Zeit gelaufen ist. In diesem Fall gibt clock() alles zurück, nur nicht 0. Deshalb müssen Sie auch in der Warteschleife in Zeile (03) den Wert now (in dieser Variablen haben Sie am Anfang den Zeitpunkt des Funktionsaufrufs gesichert) von dem Rückgabewert von clock() subtrahieren. Solange der Unterschied zwischen clock() und now den Wert in millis nicht überschreitet, wird die while-Schleife in Zeile (03) ausgeführt. Anschließend kehrt die Funktion ohne Rückgabewert zurück.

Listing 15.1 zeigt, wie Sie nun das Ausgangsproblem dieses Kapitels mit einem Programm lösen können, das genau zehn Sekunden lang wartet und sich dann beendet:

00  // Kapitel15/warteschleife.c
01 #include<stdio.h>
02 #include<time.h>

03 void delay(unsigned long int millis) {
04 // millis*=1000; // Beim Raspberry Pi diese Zeile einfügen.
05 unsigned long int now=clock(); // Zeit am Einsprungspunkt
06 while ((clock()-now)<millis) { } // Warteschleife
07 }

08 int main(void) {
09 delay(10000);
10 return 0;
11 }

Listing 15.1    warteschleife.c verwendet die Funktion clock() aus time.h, um eine präzise Zeit lang zu warten.

Dieses Beispiel funktioniert sehr präzise und kann sogar in Spielen verwendet werden, z. B. um die Bewegung von Monstern exakt zu steuern. Leider hat diese Vorgehensweise aber auch einen Haken: Es gibt nicht nur PCs, sondern auch Mikrocontroller und Kleincomputer wie den Raspberry Pi, die Zeitangaben stets in Mikrosekunden ausdrücken. In diesem Fall könnten Sie die Funktion delay() leicht per Hand anpassen, was aber zu nicht portablem Code führt. Zum Glück gibt es aber für die delay()-Funktion Lösungen, die dem POSIX-Standard entsprechen und somit auf jedem System laufen, auch auf Linux/Unix. Im nächsten Abschnitt stellen wir eine solche portable Lösung vor.