Как правильно использовать printf для печати часов t?

в настоящее время я использую явное приведение к unsigned long long и с помощью %llu для печати, но так как size_t имеет %z спецификатор, почему не clock_t есть?

для этого даже макроса нет. Возможно, я могу предположить, что в системе x64 (OS и CPU) size_t - это 8 байт (и даже в этом случае, они предоставили %z), а насчет clock_t?

5 ответов


кажется, нет идеального способа. Корень проблемы в том, что clock_t может быть целочисленным или с плавающей точкой.

clock_t может быть типом с плавающей точкой

As Бастьен Леонар упоминает для POSIX (go upvote him), С99 проект 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 для типов с плавающей запятой:как получить самый большой тип данных с плавающей запятой точности implemenation и его спецификатор printf? поэтому, если завтра выйдет более крупный тип с плавающей запятой, его можно будет использовать и сломать вашу реализацию.

  • если clock_t - это целое число, приведение к float хорошо определено для использования ближайшего возможного float. Вы можете потерять точность, но это не будет иметь большого значения по сравнению с абсолютным значением и произойдет только в течение огромного количества времени, например long int в x86 80-битный float с 64-битным значимым, что составляет миллионы лет в секундах.

перейти upvote лимонад кто сказал что-то подобное.

если вы предполагаете, что это целое число, используйте %ju и uintmax_t

хотя unsigned long long в настоящее время является самым большим стандартным целочисленным типом:

так что лучше всего typecast к самому большому целочисленному типу без знака:

#include <stdint.h>

printf("%ju", (uintmax_t)(clock_t)1);

uintmax_t is гарантированно иметь размер максимально возможного целого размера на машине.

uintmax_t и в printf %ju были введены в c99 и gcc, например, реализует их.

в качестве бонуса, это решает раз и навсегда вопрос о том, как надежно printf целочисленные типы (что, к сожалению, не обязательно для clock_t).

что может пойти не так, если он был двойным:

  • если слишком большой, чтобы поместиться в целое число, неопределенное поведение
  • гораздо меньше, чем 1, округляется до 0, и вы ничего не увидите

поскольку эти последствия намного жестче, чем целочисленное преобразование в float, использование float, вероятно, лучше.

на glibc 2.21 это целое число

в руководстве говорится, что с помощью double это лучшая идея:

в системах GNU/Linux и GNU/Hurd clock_t эквивалентно long int и CLOCKS_PER_SEC является целочисленным значением. Но в других системах clock_t и макрос CLOCKS_PER_SEC могут быть целочисленными или типами с плавающей запятой. Приведение значений времени CPU к двойному, как в примере выше, гарантирует, что такие операции, как арифметика и печать, работают правильно и последовательно независимо от базового представления.

в glibc 2.21:

посмотреть также


Это, вероятно, потому, что тики часов не очень четко определены. Вы можете преобразовать его в секунды и распечатать его как double:

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

макрос CLOCKS_PER_SEC расширяется до выражения, представляющего количество тактов в секунду.


насколько я знаю, вы это делаете лучше. За исключением того, что clock_t может быть вещественного типа:

time_t и clock_t должны быть целочисленными или вещественно-плавающими типами.

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


стандарт C должен вместить большое разнообразие архитектур, что делает невозможным сделать какие-либо дополнительные гарантии, кроме того, что внутренний тип часов является арифметическим.

в большинстве случаев вас интересуют временные интервалы, поэтому я бы преобразовал разницу в тактах в миллисекунды. Ан unsigned long достаточно большой, чтобы представлять интервал почти 50 дней, даже если его 32 бит, поэтому он должен быть достаточно большим для большинства случаев:

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

один из способов-использовать