Ich verwende derzeit eine explizite Besetzung für unsigned long long
und verwenden %llu
um es zu drucken, aber da size_t
hat die %z
Spezifizierer, warum nicht clock_t
habe eine?
Es gibt nicht einmal ein Makro dafür. Vielleicht kann ich davon ausgehen, dass auf einem x64-System (Betriebssystem und CPU) size_t
ist 8 Bytes lang (und selbst in diesem Fall haben sie bereitgestellt %z
), aber was ist mit clock_t
?
Es scheint keinen perfekten Weg zu geben. Die Wurzel des Problems ist das clock_t
kann entweder ganzzahlig oder Gleitkomma sein.
clock_t kann ein Fließkommatyp sein
Wie Bastien Léonard für POSIX erwähnt (wählen Sie ihn positiv), C99 N1256-Entwurf 7.23.1/3 sagt auch:
[clock_t is] arithmetische Typen, die Zeiten darstellen können
und 6.2.5/18:
Integer- und Floating-Typen werden gemeinsam als arithmetische Typen bezeichnet.
und der Standard definiert den arithmetischen Typ entweder als ganze Zahlen oder als Fließkommatypen.
Wenn Sie durch CLOCKS_PER_SEC dividieren, verwenden Sie long double
Der Rückgabewert von clock()
ist die Implementierung definiert, und die einzige Möglichkeit, die Standardbedeutung daraus zu ziehen, besteht darin, durch zu teilen CLOCKS_PER_SEC
So finden Sie die Anzahl der Sekunden:
clock_t t0 = clock();
/* Work. */
clock_t t1 = clock();
printf("%Lf", (long double)(t1 - t0));
Dies ist aus den beiden folgenden Gründen gut genug, wenn auch nicht perfekt:
-
es scheint kein Analogon zu geben intmax_t
für Gleitkommatypen: Wie erhält man den Gleitkommadatentyp mit der größten Genauigkeit der Implementierung und seinen printf-Spezifizierer? Wenn also morgen ein größerer Gleitkommatyp herauskommt, könnte er verwendet werden und Ihre Implementierung beschädigen.
-
wenn clock_t
eine Ganzzahl ist, ist die Umwandlung in Float gut definiert, um das nächstmögliche Float zu verwenden. Sie können an Genauigkeit verlieren, aber es würde im Vergleich zum absoluten Wert nicht viel ausmachen und nur für sehr lange Zeiträume auftreten, z long int
in x86 ist das 80-Bit-Float mit 64-Bit signifikant, was Millionen von Jahren in Sekunden bedeutet.
Stimmen Sie Lemonad zu, die etwas Ähnliches gesagt hat.
Wenn Sie annehmen, dass es sich um eine Ganzzahl handelt, verwenden Sie %ju und uintmax_t
Obwohl unsigned long long
ist derzeit der größtmögliche Standard-Ganzzahltyp:
- Ein größerer könnte in Zukunft herauskommen
- der Standard erlaubt bereits explizit größere implementierungsdefinierte Typen (ein großes Lob an @FUZxxl) und
clock_t
könnte einer davon sein
Daher ist es am besten, den größtmöglichen vorzeichenlosen ganzzahligen Typ umzuwandeln:
#include <stdint.h>
printf("%ju", (uintmax_t)(clock_t)1);
uintmax_t
hat garantiert die Größe der größtmöglichen ganzzahligen Größe auf der Maschine.
uintmax_t
und sein printf-Spezifizierer %ju
wurden in c99 eingeführt und gcc zum Beispiel implementiert sie.
Als Bonus löst dies ein für alle Mal die Frage, wie man das zuverlässig macht printf
Integer-Typen (was leider nicht unbedingt der Fall ist für clock_t
).
Was könnte schief gehen, wenn es ein Double wäre:
- wenn zu groß, um in die Ganzzahl zu passen, undefiniertes Verhalten
- viel kleiner als 1, wird auf 0 gerundet und Sie werden nichts sehen
Da diese Konsequenzen viel härter sind als die Konvertierung von Integer zu Float, ist die Verwendung von Float wahrscheinlich eine bessere Idee.
Auf glibc 2.21 ist es eine ganze Zahl
Das Handbuch sagt, dass mit double
ist eine bessere idee:
Auf GNU/Linux- und GNU/Hurd-Systemen ist clock_t äquivalent zu long int und CLOCKS_PER_SEC ist ein ganzzahliger Wert. Aber in anderen Systemen können sowohl clock_t als auch das Makro CLOCKS_PER_SEC entweder Integer- oder Fließkommatypen sein. Durch das Verdoppeln von CPU-Zeitwerten wie im obigen Beispiel wird sichergestellt, dass Operationen wie Arithmetik und Drucken unabhängig von der zugrunde liegenden Darstellung ordnungsgemäß und konsistent funktionieren.
In glibc 2.21:
-
clock_t
ist long int
:
-
clock()
in Linux wird mit implementiert sys_clock_gettime
:
man clock_gettime
sagt uns, dass es a zurückgibt struct timespec
was in gcc enthält long int
Felder.
Die zugrunde liegende Implementierung gibt also wirklich ganze Zahlen zurück.
Siehe auch
- Wie drucke ich Typen unbekannter Größe wie ino_t?
- Wie verwende ich printf, um off_t, nlink_t, size_t und andere spezielle Typen anzuzeigen?
Soweit ich weiß, ist die Art und Weise, wie Sie es tun, die beste. Außer dass clock_t
kann ein echter Typ sein:
time_t
und clock_t
müssen Integer- oder Real-Floating-Typen sein.
http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html
Das liegt wahrscheinlich daran, dass der Zeittakt keine sehr gut definierte Einheit ist. Sie können es in Sekunden umwandeln und doppelt drucken:
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 Takte pro Sekunde darstellt.
Der C-Standard muss eine Vielzahl von Architekturen berücksichtigen, was es unmöglich macht, abgesehen davon, dass der interne Takttyp arithmetisch ist, keine weiteren Garantien zu geben.
In den meisten Fällen interessieren Sie sich für Zeitintervalle, also würde ich die Differenz in Takten in Millisekunden umwandeln. Ein unsigned long
ist groß genug, um ein Intervall von fast 50 Tagen darzustellen, selbst wenn es 32 Bit ist, also sollte es für die meisten Fälle groß genug sein:
clock_t start;
clock_t end;
unsigned long millis = (end - start) * 1000 / CLOCKS_PER_SEC;
Eine Möglichkeit ist die Verwendung von gettimeofday
Funktion. Den Unterschied findet man mit dieser Funktion:
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;
}