什么是使用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_t
很long int
:- time / time.h将其设置为
__clock_t
- bits / types.h将其设置为
__CLOCK_T_TYPE
- bits /
__SLONGWORD_TYPE
将其设置为__SLONGWORD_TYPE
- bits / types.h将其设置为
long int
- time / time.h将其设置为
-
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
。所以底层的实现真的返回整数。
- sysdeps / unix / sysv / linux / clock.c调用
也可以看看
- 如何打印类似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_t
和clock_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; }