Ich verwende derzeit eine explizite Umwandlung in unsigned long long
und verwende %llu
, um es zu drucken. Da jedoch size_t
den %z
-Bezeichner hat, warum hat clock_t
keinen?
Es gibt nicht einmal ein Makro dafür. Vielleicht kann ich davon ausgehen, dass size_t
auf einem x64-System (Betriebssystem und CPU) 8 Byte lang ist (und sogar in diesem Fall haben sie %z
bereitgestellt), aber was ist mit clock_t
?
Es scheint keinen perfekten Weg zu geben. Die Ursache des Problems ist, dass clock_t
entweder eine Ganzzahl oder ein Gleitkomma sein kann.
clock_t kann ein Gleitkommatyp sein
Wie von Bastien Léonard erwähnt für POSIX (geht auf ihn hinaus), C99 N1256 Draft 7.23.1/3 sagt auch:
[clock_t is] arithmetische Typen, die Zeiten darstellen können
und 6.2.5/18:
Ganzzahlige und gleitende Typen werden zusammen als Arithmetiktypen bezeichnet.
und der Standard definiert den arithmetischen Typ entweder als Ganzzahl oder als Gleitkommatyp.
Wenn Sie durch CLOCKS_PER_SEC teilen, verwenden Sie long double.
Der Rückgabewert von clock()
ist implementierungsdefiniert. Die Standardbedeutung kann nur durch die Division durch CLOCKS_PER_SEC
erreicht werden, um die Anzahl der Sekunden zu ermitteln:
clock_t t0 = clock();
/* Work. */
clock_t t1 = clock();
printf("%Lf", (long double)(t1 - t0));
Das ist gut genug, wenn auch nicht perfekt, aus zwei Gründen:
es scheint kein Analogon zu intmax_t
für Fließkommatypen zu geben: Wie erhalte ich den Fließkommadatentyp mit der höchsten Genauigkeit und seinen printf-Spezifizierer? Wenn also morgen ein größerer Fließkommatyp herauskommt, könnte es sein verwendet und brechen Sie Ihre Implementierung.
wenn clock_t
eine ganze Zahl ist, ist die Umwandlung in Float so definiert, dass der nächstliegende Float verwendet wird. Sie verlieren möglicherweise die Genauigkeit, aber im Vergleich zum absoluten Wert ist dies nicht von Bedeutung und würde nur für sehr lange Zeit geschehen, z. long int
in x86 ist der 80-Bit-Float mit 64 Bit, was Millionen von Jahren in Sekunden ist.
Go upvote lemonad der etwas ähnliches gesagt hat.
Wenn Sie annehmen, dass es eine ganze Zahl ist, verwenden Sie% ju und uintmax_t.
Obwohl unsigned long long
derzeit der größte mögliche Standardwert ist:
clock_t
könnte einer von ihnen seindaher ist es am besten, den größtmöglichen vorzeichenlosen Integer-Typ zu konvertieren:
#include <stdint.h>
printf("%ju", (uintmax_t)(clock_t)1);
uintmax_t
hat garantiert die Größe der größtmöglichen Ganzzahl auf der Maschine.
uintmax_t
und sein printf-Spezifizierer %ju
wurden in c99 eingeführt, und gcc implementiert sie zum Beispiel.
Als Bonus löst dies ein für alle Mal die Frage, wie zuverlässig printf
Integer-Typen (was leider nicht unbedingt der Fall für clock_t
ist).
Was könnte schief gehen, wenn es ein Double wäre:
Da diese Konsequenzen viel härter sind als die Umwandlung von Ganzzahl in Float, ist die Verwendung von Float wahrscheinlich eine bessere Idee.
Auf glibc 2.21 ist es eine ganze Zahl
Das Handbuch besagt, dass die Verwendung von double
eine bessere Idee ist:
Auf GNU/Linux- und GNU/Hurd-Systemen entspricht clock_t einem long int und CLOCKS_PER_SEC ist ein ganzzahliger Wert. In anderen Systemen können clock_t und das Makro CLOCKS_PER_SEC jedoch entweder Ganzzahl- oder Gleitkommatypen sein. Durch das Verdoppeln der CPU-Zeitwerte (wie im obigen Beispiel) wird sichergestellt, dass Vorgänge wie Arithmetik und Drucken ordnungsgemäß und konsistent funktionieren, unabhängig von der zugrunde liegenden Darstellung.
In Glibc 2.21:
clock_t
ist long int
:
__clock_t
__CLOCK_T_TYPE
__SLONGWORD_TYPE
long int
clock()
in Linux wird mit sys_clock_gettime
implementiert:
__clock_gettime
aufSYSDEP_GETTIME_CPU
aufSYSCALL_GETTIME
auf, der schließlich einen Inline-Systemaufruf durchführtman clock_gettime
sagt uns, dass es einen struct timespec
zurückgibt, der in GCC long int
-Felder enthält.
Die zugrunde liegende Implementierung gibt also wirklich ganze Zahlen zurück.
Siehe auch
Dies liegt wahrscheinlich daran, dass die Uhrenzähler keine sehr gut definierte Einheit sind. Sie können es in Sekunden konvertieren und es als Doppelter ausgeben:
time_in_seconds = (double)time_in_clock_ticks / (double)CLOCKS_PER_SEC;
printf("%g seconds", seconds);
Das Makro CLOCKS_PER_SEC wird zu einem Ausdruck erweitert, der die Anzahl der Taktstriche in einer Sekunde darstellt.
Soweit ich weiß, ist das Beste, was Sie tun. Außer dass clock_t
ein reeller Typ sein kann:
time_t
undclock_t
müssen vom Typ Integer oder Real Floating sein.
http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html
Der C-Standard muss eine Vielzahl von Architekturen aufnehmen, so dass neben der Tatsache, dass der interne Uhrentyp arithmetisch ist, keine weiteren Garantien möglich sind.
In den meisten Fällen interessieren Sie sich für Zeitintervalle, daher würde ich die Differenz der Uhr in Millisekunden umrechnen. Ein unsigned long
ist groß genug, um ein Intervall von fast 50 Tagen darzustellen, auch wenn sein 32-Bit-Wert für die meisten Fälle groß genug ist:
clock_t start;
clock_t end;
unsigned long millis = (end - start) * 1000 / CLOCKS_PER_SEC;
Eine Möglichkeit ist die Verwendung der Funktion gettimeofday
. Man kann den Unterschied anhand dieser Funktion feststellen:
unsigned long diff(struct timeval second, struct timeval first)
{
struct timeval lapsed;
struct timezone tzp;
unsigned long t;
if (first.tv_usec > second.tv_usec) {
second.tv_usec += 1000000;
second.tv_sec--;
}
lapsed.tv_usec = second.tv_usec - first.tv_usec;
lapsed.tv_sec = second.tv_sec - first.tv_sec;
t = lapsed.tv_sec*1000000 + lapsed.tv_usec;
printf("%lu,%lu - %lu,%lu = %ld,%ld\n",
second.tv_sec, second.tv_usec,
first.tv_sec, first.tv_usec,
lapsed.tv_sec, lapsed.tv_usec);
return t;
}