Wie kann printf zum Drucken von clock_t verwendet werden?

Ich verwende derzeit eine explizite %llu zu unsigned long long und verwende %llu , um sie zu drucken, aber da size_t den %z Spezifizierer hat, warum hat clock_t keinen?

Es gibt nicht einmal ein Makro dafür. Vielleicht kann ich davon ausgehen, dass auf einem x64-System (OS und CPU) size_t 8 Bytes lang ist (und sogar in diesem Fall haben sie %z bereitgestellt), aber was ist mit clock_t ?

    Es scheint keinen perfekten Weg zu geben. Der clock_t des Problems ist, dass clock_t entweder Integer oder Fließkomma sein kann.

    clock_t kann ein Gleitkommatyp sein

    Wie Bastien Léonard für POSIX erwähnt (gehe upvote ihn), sagt C99 N1256 Entwurf 7.23.1 / 3 auch, dass:

    [clock_t] ist arithmetische Typen, die Zeiten darstellen können

    und 6.2.5 / 18:

    Integer und Floating-Typen werden zusammen als arithmetische Typen bezeichnet.

    und der Standard definiert den arithmetischen Typ entweder als ganze Zahlen oder Gleitkommatypen.

    Wenn Sie nach CLOCKS_PER_SEC dividieren, verwenden Sie long double

    Der Rückgabewert von clock() ist implementation definiert, und die einzige Möglichkeit, Standardbedeutung daraus zu erhalten, ist die Division durch CLOCKS_PER_SEC , um die Anzahl der Sekunden zu finden:

     clock_t t0 = clock(); /* Work. */ clock_t t1 = clock(); printf("%Lf", (long double)(t1 - t0)); 

    Das ist gut genug, obwohl nicht perfekt, aus den folgenden zwei Gründen:

    • Für Gleitkommatypen scheint es kein Analog zu intmax_t zu geben: Wie erhält man den größten Präzisions-Fließkommadatentyp der Implementierung und seinen printf-Spezifizierer? Wenn also morgen ein größerer Fließkommatyp herauskommt, könnte er verwendet werden und Ihre Implementierung unterbrechen.

    • Wenn clock_t eine Ganzzahl ist, ist die zu clock_t Darstellung gut definiert, um den nächstmöglichen clock_t zu verwenden. Sie können die Genauigkeit verlieren, aber es wäre nicht viel im Vergleich zum absoluten Wert, und würde nur für sehr viel Zeit passieren, zB long int in x86 ist die 80-Bit Float mit 64-Bit signifikant, was Millionen von Jahren in Sekunden.

    Gehen Sie upvote Lemonad, der etwas Ähnliches sagte.

    Wenn Sie annehmen, dass es sich um eine Ganzzahl handelt, verwenden Sie% ju und uintmax_t

    Obwohl unsigned long long derzeit der größte mögliche unsigned long long ist:

    • ein größeres könnte in der Zukunft herauskommen
    • Der Standard erlaubt bereits explizit größere Implementierungsdefinitionen (kudos an @FUZxxl) und clock_t könnte einer davon sein

    Daher ist es am besten, auf den größtmöglichen vorzeichenlosen Integer-Typ zu tippen:

     #include  printf("%ju", (uintmax_t)(clock_t)1); 

    uintmax_t hat garantiert die Größe der größtmöglichen Integer-Größe auf der Maschine.

    uintmax_t und sein printf specifier %ju wurden in c99 eingeführt und gcc zum Beispiel implementiert sie.

    Als Bonus triggers dies ein für clock_t die Frage, wie man ganzzahlige Typen zuverlässig printf (was leider nicht unbedingt der Fall für clock_t ).

    Was könnte schief gehen, wenn es ein Doppel war:

    • wenn zu groß, um in die Ganzzahl zu passen, undefiniertes Verhalten
    • viel kleiner als 1, wird auf 0 gerundet und du wirst nichts sehen

    Da diese Konsequenzen viel schärfer sind als die Integer-Float-Konvertierung, ist die Verwendung von Float wahrscheinlich eine bessere Idee.

    Auf Glibc 2.21 ist es eine ganze Zahl

    Das Handbuch sagt, dass die Verwendung von double eine bessere Idee ist:

    Auf GNU / Linux- und GNU / Hurd-Systemen ist clock_t gleich lang int und CLOCKS_PER_SEC ist ein ganzzahliger Wert. In anderen Systemen können sowohl clock_t als auch das Makro CLOCKS_PER_SEC entweder Integer- oder Gleitkommatypen sein. Wenn Sie CPU-Zeitwerte wie im obigen Beispiel verdoppeln, wird sichergestellt, dass Operationen wie Arithmetik und Druck unabhängig von der zugrunde liegenden Darstellung ordnungsgemäß und konsistent ausgeführt werden.

    In glibc 2.21:

    • clock_t ist long int :

      • time / time.h setzt es auf __clock_t
      • bits / types.h setzt es auf __CLOCK_T_TYPE
      • bits / typesizes.h setzt es auf __SLONGWORD_TYPE
      • bits / types.h setzt es auf long int
    • clock() in Linux wird mit sys_clock_gettime implementiert:

      • sysdeps / unix / sysv / linux / clock.c ruft __clock_gettime
      • sysdeps / unix / clock_gettime.c ruft SYSDEP_GETTIME_CPU
      • sysdeps / unix / sysv / linux / clock_gettime.c ruft SYSCALL_GETTIME das schließlich einen Inline-Systemaufruf durchführt

      man clock_gettime , sagt uns, dass es eine struct timespec die in GCC long int Felder enthält.

      Die zugrundeliegende Implementierung gibt also ganze Zahlen zurück.

    Siehe auch

    • Wie drucke ich Typen unbekannter Größe wie ino_t?
    • Wie verwende printf um off_t, nlink_t, size_t und andere Sondertypen anzuzeigen?

    Es ist wahrscheinlich, weil Clock Ticks keine sehr gut definierte Einheit ist. Sie können es in Sekunden umwandeln und es als Doppel drucken:

     time_in_seconds = (double)time_in_clock_ticks / (double)CLOCKS_PER_SEC; printf("%g seconds", seconds); 

    Das CLOCKS_PER_SEC-Makro wird zu einem Ausdruck erweitert, der die Anzahl der Taktgeber in Sekunden angibt.

    Soweit ich weiß, ist die Art, wie Sie es tun, die Beste. Außer dass clock_t ein realer Typ sein kann:

    time_t und clock_t sollen Integer- oder Real-Floating-Typen sein.

    http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html

    Der C-Standard muss eine große Vielfalt von Architekturen aufnehmen, was es unmöglich macht, weitere Garantien zu geben, abgesehen davon, dass der interne Uhrentyp arithmetisch ist.

    In den meisten Fällen sind Sie an Zeitintervallen interessiert, also würde ich den Unterschied in den Takt-Ticks in Millisekunden umrechnen. Ein unsigned long ist groß genug, um ein Intervall von fast 50 Tagen darzustellen, selbst wenn es 32bit 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 besteht darin, die function gettimeofday verwenden. Mit dieser function kann man den Unterschied finden:

     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; }