我目前正在使用显式强制转换unsigned long long
并使用%llu
来打印它,但是既然size_t
有说明%z
符,为什么没有clock_t
呢?
甚至没有宏。也许我可以假设在 x64 系统(操作系统和 CPU)size_t
上的长度为 8 个字节(即使在这种情况下,他们也提供了%z
),但是呢clock_t
?
似乎没有完美的方法。问题的根源在于它clock_t
可以是整数或浮点数。
clock_t 可以是浮点类型
正如Bastien Léonard为 POSIX 提到的(给他投票),C99 N1256 草案7.23.1/3 也说:
[clock_t is] 能够表示时间的算术类型
和 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_t
浮点类型似乎没有类似物:如何获得实现的最大精度浮点数据类型及其 printf 说明符?因此,如果明天出现更大的浮点类型,它可能会被使用并破坏您的实现。
如果clock_t
是整数,则强制转换为浮点数被明确定义为使用最接近的浮点数。您可能会失去精度,但与绝对值相比,这无关紧要,并且只会在很长一段时间内发生,例如long int
在 x86 中是具有 64 位有效位的 80 位浮点数,即数百万年以秒为单位。
去投票给说类似话的柠檬水。
如果您认为它是整数,请使用 %ju 和 uintmax_t
虽然unsigned long long
是目前可能的最大标准整数类型:
clock_t
可能是其中之一因此最好将类型转换为可能的最大无符号整数类型:
#include <stdint.h>
printf("%ju", (uintmax_t)(clock_t)1);
uintmax_t
保证具有机器上可能的最大整数大小的大小。
uintmax_t
它的 printf 说明符%ju
是在 c99 中引入的,例如 gcc 实现了它们。
作为奖励,这一劳永逸地解决了如何可靠地printf
整数类型的问题(不幸的是,这不一定是这种情况clock_t
)。
如果它是双重的,可能会出现什么问题:
由于这些后果比整数到浮点数的转换要严重得多,因此使用浮点数可能是一个更好的主意。
在 glibc 2.21 上它是一个整数
该手册说使用double
是一个更好的主意:
在 GNU/Linux 和 GNU/Hurd 系统上,clock_t 等价于 long int,而 CLOCKS_PER_SEC 是一个整数值。但在其他系统中,clock_t 和宏 CLOCKS_PER_SEC 都可以是整数或浮点类型。如上例所示,将 CPU 时间值转换为双倍可确保算术和打印等操作正确且一致地工作,无论底层表示是什么。
在 glibc 2.21 中:
clock_t
是long int
:
__clock_t
__CLOCK_T_TYPE
__SLONGWORD_TYPE
long int
clock()
在 Linux 中是通过以下方式实现的sys_clock_gettime
:
__clock_gettime
SYSDEP_GETTIME_CPU
SYSCALL_GETTIME
,最终进行内联系统调用man clock_gettime
, 告诉我们它返回struct timespec
GCC 中包含long int
字段的 which。
所以底层实现真的返回整数。
也可以看看
据我所知,你的做法是最好的。除了这clock_t
可能是一个真实的类型:
time_t
并且clock_t
应该是整数或实浮点类型。
http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html
这可能是因为时钟滴答不是一个非常明确的单位。您可以将其转换为秒并将其打印为双精度:
time_in_seconds = (double)time_in_clock_ticks / (double)CLOCKS_PER_SEC;
printf("%g seconds", seconds);
CLOCKS_PER_SEC 宏扩展为表示一秒内时钟滴答数的表达式。
C 标准必须适应各种各样的体系结构,这使得除了内部时钟类型是算术这一事实之外无法做出任何进一步的保证。
在大多数情况下,您对时间间隔感兴趣,因此我会将时钟滴答的差异转换为毫秒。Anunsigned long
足够大,即使它是 32 位,也足以表示近 50 天的间隔,因此对于大多数情况它应该足够大:
clock_t start;
clock_t end;
unsigned long millis = (end - start) * 1000 / CLOCKS_PER_SEC;
一种方法是使用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;
}