使用printf打印clock_t的正确方法是什么?

时间:2009-07-04 23:05:55

标签: c io printf clock

我目前正在使用unsigned long long显式转换并使用%llu进行打印,但由于size_t具有%z说明符,为什么不clock_t 1}}有一个?

甚至没有宏观。也许我可以假设在x64系统上(操作系统和CPU)size_t的长度为8个字节(即使在这种情况下,它们也提供了%z),但是clock_t呢?

5 个答案:

答案 0 :(得分:25)

似乎没有完美的方式。问题的根源是clock_t可以是整数或浮点。

clock_t可以是浮点类型

作为POSIX的Bastien Léonard mentions(向上投票),C99 N1256 draft 7.23.1 / 3也说:

  

[clock_t]是能够表示时间的算术类型

和6.2.5 / 18:

  

整数和浮点类型统称为算术类型。

,标准将算术类型定义为整数或浮点类型。

如果您将除以CLOCKS_PER_SEC,请使用long double

clock()的返回值是实现定义的,获得标准含义的唯一方法是除以CLOCKS_PER_SEC来查找秒数:

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

这很好,虽然不完美,但有以下两个原因:

  • 对于浮点类型似乎没有类似于intmax_tHow to get the largest precision floating point data type of implemenation and its printf specifier?因此,如果明天出现更大的浮点类型,则可以使用它并破坏您的实现。

  • 如果clock_t是一个整数,则将float定义为使用最近的float。你可能会失去精确度,但与绝对值相比它并不重要,并且只会在很长一段时间内发生,例如: x86中的long int是具有64位有效值的80位浮点数,这是几百万年的秒数。

Go upvote lemonad谁说了类似的东西。

如果您认为它是一个整数,请使用%ju和uintmax_t

虽然unsigned long long是目前可能的最大标准整数类型:

因此最好将类型转换为可能的最大无符号整数类型:

#include <stdint.h>

printf("%ju", (uintmax_t)(clock_t)1);
保证

uintmax_t具有机器上可能的最大整数大小。

uintmax_t及其printf说明符%ju在c99中引入,例如gcc实现它们。

作为奖励,这一劳永逸地解决了如何可靠printf整数类型的问题(遗憾的是clock_t不一定是这种情况)。

如果它是双重的话会出现什么问题:

  • 如果太大而无法适应整数,未定义的行为
  • 远小于1,将四舍五入为0,你将看不到任何东西

由于这些后果比整数到浮点转换要严厉得多,因此使用float可能是一个更好的主意。

在glibc 2.21上,它是一个整数

手册说使用double是一个更好的主意:

  

在GNU / Linux和GNU / Hurd系统上,clock_t等效于long int,CLOCKS_PER_SEC是整数值。但在其他系统中,clock_t和宏CLOCKS_PER_SEC都可以是整数或浮点类型。将CPU时间值转换为加倍,如上例所示,确保算术和打印等操作无论底层表示是什么都能正常且一致地工作。

在glibc 2.21中:

另见

答案 1 :(得分:11)

这可能是因为时钟滴答不是一个非常明确的单位。您可以将其转换为秒并将其打印为double:

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

CLOCKS_PER_SEC宏扩展为表示一秒钟内时钟滴答数的表达式。

答案 2 :(得分:11)

据我所知,你所做的事情是最好的。除了clock_t可能是真实的类型:

  

time_tclock_t应为整数或实数浮点类型。

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

答案 3 :(得分:3)

C标准必须适应各种各样的架构,除了内部时钟类型是算术的事实之外,它不可能做出任何进一步的保证。

在大多数情况下,您对时间间隔感兴趣,因此我将时钟滴答的差异转换为毫秒。 unsigned long大到足以代表近50天的间隔,即使它是32位,所以对于大多数情况它应该足够大:

clock_t start;
clock_t end;
unsigned long millis = (end - start) * 1000 / CLOCKS_PER_SEC;

答案 4 :(得分:1)

一种方法是使用gettimeofday功能。可以使用此函数找到差异:

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