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

我目前使用一个明确的%llu转换为unsigned long long并使用%llu来打印它,但是由于size_t具有%z说明符,为什么clock_t没有?

甚至没有一个macros。 也许我可以假设在一个x64系统(OS和CPU) size_t是8字节的长度(甚至在这种情况下,他们提供了%z ),但是clock_t呢?

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

clock_t可以是浮点types

正如BastienLéonard 提到 POSIX(提高他), C99 N1256草案 7.23.1 / 3也说:

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

和6.2.5 / 18:

整型和浮点types统称为算术types。

标准将算术types定义为整数或浮点types。

如果除以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_t浮点types: 如何获得最大的精度浮点数据types的实现和它的printf说明符? 所以如果一个更大的浮点types明天出来,它可以被使用,并打破你的实现。

  • 如果clock_t是一个整数,那么可以使用最接近的浮点数来定义浮点数。 你可能会失去精度,但是与绝对值相比并不重要,只会发生在大量的时间,例如,x86中的long int是64位重要的80位浮点数,这是数百万年秒。

去赞扬说类似的柠檬水 。

如果你假设它是一个整数,使用%ju和uintmax_t

尽pipeunsigned long long是目前可能的最大标准整数types:

  • 未来可能会出现更大的一个
  • 该标准已经明确允许更大的实现定义types (荣誉@FUZxxl)和clock_t可能是其中之一

所以最好将types转换为最大的无符号整数types:

 #include <stdint.h> printf("%ju", (uintmax_t)(clock_t)1); 

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

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

作为一个奖励,这一劳永逸地解决了如何可靠地printf整数types的问题(这对于clock_t不是必须的)。

如果是双重的话,会出现什么问题呢?

  • 如果太大以致无法放入整数,则会导致未定义的行为
  • 比1小得多,会变成0,你什么都看不到

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

在glibc 2.21上是一个整数

手册上说使用double是个好主意:

在GNU / Linux和GNU / Hurd系统上,clock_t等同于long int,CLOCKS_PER_SEC是一个整数值。 但是在其他系统中,clock_t和macrosCLOCKS_PER_SEC都可以是整数或浮点types。 如上例所示,将CPU时间值加倍,可以确保诸如算术和打印等操作正确无误地执行,而不pipe底层表示是什么。

在glibc 2.21中:

  • clock_tlong int

    • time / time.h将其设置为__clock_t
    • bits / types.h将其设置为__CLOCK_T_TYPE
    • bits / __SLONGWORD_TYPE将其设置为__SLONGWORD_TYPE
    • bits / types.h将其设置为long int
  • Linux中的clock()使用sys_clock_gettime来实现:

    • sysdeps / unix / sysv / linux / clock.c调用__clock_gettime
    • sysdeps / unix / clock_gettime.c调用SYSDEP_GETTIME_CPU
    • sysdeps / unix / sysv / linux / clock_gettime.c调用SYSCALL_GETTIME ,最终进行内联系统调用

    man clock_gettime告诉我们它返回一个在GCC中包含long int字段的struct timespec

    所以底层的实现真的返回整数。

也可以看看

  • 如何打印类似ino_t的未知大小的types?
  • 如何使用printf显示off_t,nlink_t,size_t和其他特殊types?

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

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

CLOCKS_PER_SECmacros扩展为一秒钟内表示时钟滴答数的expression式。

据我所知,你所做的是最好的。 除了clock_t可能是一个真正的types:

time_tclock_t应该是整型或实型浮点型。

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

C标准必须适应各种各样的体系结构,除了内部时钟types是算术的这一事实之外,不可能做出进一步的保证。

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

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

一种方法是使用gettimeofday函数。 人们可以使用这个函数find差异:

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