使用 printf 打印clock_t 的正确方法是什么? [英] What’s the correct way to use printf to print a clock_t?

查看:28
本文介绍了使用 printf 打印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:

  • 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:

  • 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_tlong 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 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆