Was ist der richtige Weg, um printf zu verwenden, um ein clock_t zu drucken?

Lesezeit: 7 Minuten

Benutzer-Avatar
Spidey

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?

Benutzer-Avatar
Ciro Santilli OurBigBook.com

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:

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?

  • %ju? das druckt genau ju

    – Viktor

    3. August 2013 um 8:37 Uhr

  • @Victor: Kompilierst du mit gcc -std=c99 (oder Ihrem Compiler sagen, dass er c99 verwenden soll)? Was ist Ihre Compiler-Version? Ich habe es gerade getestet und folgendes funktioniert bei mir unter gcc --version gleich gcc (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3: printf( "printf uintmax_t = %ju\n", (uintmax_t)1 );.

    – Ciro Santilli OurBigBook.com

    3. August 2013 um 9:40 Uhr


  • Ich verwende Visual Studio 2010 🙂

    – Viktor

    3. August 2013 um 13:30 Uhr

  • Es scheint, dass c99 von VS2010 nicht unterstützt wird. Lesen Sie auch, dass MS keine Pläne hat, es auf ihren Compilern zu implementieren (korrigieren Sie mich, wenn ich falsch liege). Ich würde bei der Windows-Programmierung bei C++ bleiben.

    – Ciro Santilli OurBigBook.com

    3. August 2013 um 13:47 Uhr


  • unsigned long long int ist nicht der größtmögliche ganzzahlige Typ. Plattformen können benutzerdefinierte Integer-Typen größerer Größe bereitstellen.

    – fuz

    19. Mai 2015 um 8:43 Uhr

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

  • Sehr gut ausgedrückt, ich habe vergessen, dass es sich möglicherweise um einen Gleitkommatyp handelt.

    – Spidy

    5. Juli 2009 um 3:29 Uhr

  • Gibt es eine Möglichkeit, den Gleitkommatyp mit der größtmöglichen Genauigkeit zu erhalten, und sein Bezeichner kann für ganze Zahlen verwendet werden uintmax_t und %ju? Das wäre der optimale Weg.

    – Ciro Santilli OurBigBook.com

    19. Juni 2013 um 10:22 Uhr

  • @cirosantilli: es scheint nein

    – Ciro Santilli OurBigBook.com

    19. Juni 2013 um 12:06 Uhr


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.

  • Ich nehme lieber 1) long double da es möglicherweise präziser ist. 2) Führen Sie eine einzelne Typumwandlung durch nach der Unternehmensbereich: (long double)(time_in_clock_ticks / CLOCKS_PER_SEC) nur einmal runden.

    – Ciro Santilli OurBigBook.com

    7. Juni 2015 um 8:00 Uhr

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;

Benutzer-Avatar
Rani

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

  • POSIX.1-2008 markiert gettimeofday() als obsolet, was dazu führen kann, dass bestimmte Präprozessor-Direktiven benötigt werden, damit ein Compiler auf sie verweist, wenn Sie auch Dinge wie -DXOPEN_SOURCE=600 und so weiter verwenden.

    – JohannesH

    2. Mai 2019 um 20:17 Uhr

  • POSIX.1-2008 markiert gettimeofday() als obsolet, was dazu führen kann, dass bestimmte Präprozessor-Direktiven benötigt werden, damit ein Compiler auf sie verweist, wenn Sie auch Dinge wie -DXOPEN_SOURCE=600 und so weiter verwenden.

    – JohannesH

    2. Mai 2019 um 20:17 Uhr

1385380cookie-checkWas ist der richtige Weg, um printf zu verwenden, um ein clock_t zu drucken?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy