使用 printf 打印clock_t 的正确方法是什么? [英] What’s the correct way to use printf to print a clock_t?
问题描述
我目前正在使用显式转换为 unsigned long long
并使用 %llu
打印它,但由于 size_t
具有 %z
说明符,为什么 clock_t
没有?
I'm currently using a explicit cast to unsigned long long
and using %llu
to print it, but since size_t
has the %z
specifier, why doesn't clock_t
have one?
它甚至没有一个宏.也许我可以假设在 x64 系统(操作系统和 CPU)上 size_t
的长度是 8 个字节(即使在这种情况下,他们也提供了 %z
),但是什么关于clock_t
?
There isn't even a macro for it. Maybe I can assume that on an x64 system (OS and CPU) size_t
is 8 bytes in length (and even in this case, they have provided %z
), but what about clock_t
?
推荐答案
似乎没有完美的方法.问题的根源在于 clock_t
可以是整数或浮点数.
There seems to be no perfect way. The root of the problem is that clock_t
can be either integer or floating point.
clock_t 可以是浮点类型
正如 Bastien Léonard 提到的 POSIX(给他点赞),C99 N1256 草案 7.23.1/3 也说:
As Bastien Léonard mentions for POSIX (go upvote him), C99 N1256 draft 7.23.1/3 also says that:
[clock_t is] 能够表示时间的算术类型
[clock_t is] arithmetic types capable of representing times
和 6.2.5/18:
and 6.2.5/18:
整数和浮点类型统称为算术类型.
Integer and floating types are collectively called arithmetic types.
并且标准将算术类型定义为整数或浮点类型.
and the standard defines arithmetic type as either integers or floating point types.
如果要除以 CLOCKS_PER_SEC,请使用 long double
clock()
的返回值是实现定义的,得到标准含义的唯一方法是除以 CLOCKS_PER_SEC
以找到秒数:
The return value of clock()
is implementation defined, and the only way to get standard meaning out of it is to divide by CLOCKS_PER_SEC
to find the number of seconds:
clock_t t0 = clock();
/* Work. */
clock_t t1 = clock();
printf("%Lf", (long double)(t1 - t0));
这已经足够好了,虽然还不够完美,但有以下两个原因:
This is good enough, although not perfect, for the two following reasons:
似乎没有类似于
intmax_t
的浮点类型:如何获取实现的最大精度浮点数据类型及其 printf 说明符? 那么如果一个更大的浮点类型明天出来,它可能会被使用并破坏你的实现.
there seems to be no analogue to
intmax_t
for floating point types: How to get the largest precision floating point data type of implemenation and its printf specifier? So if a larger floating point type comes out tomorrow, it could be used and break your implementation.
如果 clock_t
是一个整数,则可以很好地定义转换为浮点数以使用最接近的浮点数.您可能会失去精度,但与绝对值相比这无关紧要,并且只会在很长一段时间内发生,例如long int
在 x86 中是 80 位浮点数,64 位有效,以秒为单位表示数百万年.
if clock_t
is an integer, the cast to float is well defined to use the nearest float possible. You may lose precision, but it would not matter much compared to the absolute value, and would only happen for huge amounts of time, e.g. long int
in x86 is the 80-bit float with 64-bit significant, which is millions of years in seconds.
如果你假设它是一个整数,使用 %ju 和 uintmax_t
尽管 unsigned long long
目前是最大的标准整数类型:
Although unsigned long long
is currently the largest standard integer type possible:
- 未来可能会出现更大的
- 标准已经明确允许更大的实现定义类型(感谢@FUZxxl)和
clock_t
可能是其中之一
- a larger one could come out in the future
- the standard already explicitly allows larger implementation defined types (kudos to @FUZxxl) and
clock_t
could be one of them
所以最好将类型转换为最大的无符号整数类型:
so it is best to typecast to the largest unsigned integer type possible:
#include <stdint.h>
printf("%ju", (uintmax_t)(clock_t)1);
uintmax_t
保证具有机器上可能的最大整数大小.
uintmax_t
is guaranteed to have the size of the largest possible integer size on the machine.
uintmax_t
和它的 printf 说明符 %ju
是在 c99 中引入的,例如 gcc 实现了它们.
uintmax_t
and its printf specifier %ju
were introduced in c99 and gcc for example implements them.
作为奖励,这彻底解决了如何可靠地printf
整数类型的问题(不幸的是,clock_t
不一定是这种情况).
As a bonus, this solves once and for all the question of how to reliably printf
integer types (which is unfortunately not the necessarily the case for clock_t
).
如果是双倍会出现什么问题:
What could go wrong if it was a double:
- 如果太大而无法放入整数,则未定义行为
- 远小于 1,将四舍五入为 0,您将看不到任何内容
由于这些后果比将整数转换为浮点数要严重得多,因此使用浮点数可能是一个更好的主意.
Since those consequences are much harsher than the integer to float conversion, using float is likely a better idea.
在 glibc 2.21 上它是一个整数
手册说使用 double
是一个更好的主意:
The manual says that using double
is a better idea:
在 GNU/Linux 和 GNU/Hurd 系统上,clock_t 等价于 long int 而 CLOCKS_PER_SEC 是一个整数值.但在其他系统中,clock_t 和宏 CLOCKS_PER_SEC 都可以是整数或浮点类型.如上例所示,将 CPU 时间值转换为两倍,可确保算术和打印等操作正确且一致地工作,无论底层表示是什么.
On GNU/Linux and GNU/Hurd systems, clock_t is equivalent to long int and CLOCKS_PER_SEC is an integer value. But in other systems, both clock_t and the macro CLOCKS_PER_SEC can be either integer or floating-point types. Casting CPU time values to double, as in the example above, makes sure that operations such as arithmetic and printing work properly and consistently no matter what the underlying representation is.
在 glibc 2.21 中:
In glibc 2.21:
clock_t
是long int
:
- time/time.h 将其设置为
__clock_t
- bits/types.h 将其设置为
__CLOCK_T_TYPE
- bits/typesizes.h 将其设置为
__SLONGWORD_TYPE
- bits/types.h 将其设置为
long int
- time/time.h sets it to
__clock_t
- bits/types.h sets it to
__CLOCK_T_TYPE
- bits/typesizes.h sets it to
__SLONGWORD_TYPE
- bits/types.h sets it to
long int
clock()
在 Linux 中是通过 sys_clock_gettime
实现的:
clock()
in Linux is implemented with 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
最终进行内联系统调用
- sysdeps/unix/sysv/linux/clock.c calls
__clock_gettime
- sysdeps/unix/clock_gettime.c calls
SYSDEP_GETTIME_CPU
- sysdeps/unix/sysv/linux/clock_gettime.c calls
SYSCALL_GETTIME
which finally makes an inline system call
man clock_gettime
,告诉我们它返回一个 struct timespec
在 GCC 中包含 long int
字段.
man clock_gettime
, tells us that it returns a struct timespec
which in GCC contains long int
fields.
所以底层实现确实返回整数.
So the underlying implementation really returns integers.
另见
这篇关于使用 printf 打印clock_t 的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!