Спецификаторы формата для типов, определенных для реализации, таких как time_t
Я хочу сделать свой код более независимым от платформы/реализации. Я не знаю, как будет реализован time_t
, как на платформе, когда код компилируется. Как узнать тип t
, чтобы определить, какой спецификатор формата использовать?
...
time_t t = time(NULL);
printf("%s", t);
...
Ответы
Ответ 1
Как правило, способ отображения значения time_t
состоит в том, чтобы разбить его компоненты на struct tm
с помощью gmtime
или localtime
и отобразить их или преобразовать их по желанию с помощью strftime
или ctime
перейти непосредственно от time_t
к строке, показывающей местное время.
Если вы хотите увидеть исходное значение для какой-либо цели, стандарт C указывает, что time_t
является реальным, что означает, что он является целым или с плавающей точкой (C 2011 (N1570) 6.2.5 17). Следовательно, вы должны иметь возможность преобразовать его в double
и распечатать. Существует некоторая возможность того, что time_t
может представлять значения, которые double
не может, поэтому вам, возможно, придется защититься от этого, если вы хотите позаботиться об экзотических реализациях. Поскольку difftime
возвращает разность двух time_t
объектов как double
, кажется, что C не поддерживает time_t
с большей точностью, чем double
.
Ответ 2
Обычно вы можете использовать приведение, чтобы преобразовать операнд в некоторый тип, для которого вы знаете правильный формат.
Ваше предлагаемое решение:
time_t t = time(NULL);
printf("%s", t);
явно не будет работать, поскольку time_t
является числовым, а не char*
.
В общем случае мы знаем, что time_t
является арифметическим типом. Что-то вроде этого:
printf("%ld\n", (long)t);
вероятно, будет работать на большинстве систем. Он может выйти из строя (a), если time_t
является неподписанным типом, не более чем unsigned long
, а текущее значение t
превышает LONG_MAX
или (b), если time_t
- тип с плавающей запятой.
Если у вас есть поддержка C99, вы можете использовать long long
, что немного лучше:
printf("%lld\n", (long long)t);
Если вы действительно хотите выйти за борт с переносимостью, вы можете определить тип типа time_t
:
if ((time_t)-1 > 0) {
// time_t is an unsigned type
printf("%ju\n", (uintmax_t)t);
}
else if ((time_t)1 / 2 > 0) {
// time_t is a signed integer type
printf("%jd\n", (intmax_t)t);
}
else {
// time_t is a floating-point type (I've never seen this)
printf("%Lg\n", (long double)t);
}
Возможно, вы захотите изменить формат %Lg
на что-то вроде %Lf
или %.10Lf
, в зависимости от того, какой формат вывода вы хотите.
Опять же, это предполагает поддержку C99 - и вам понадобится #include <stdint.h>
, чтобы сделать uintmax_t
и intmax_t
видимыми.
time_t
и clock_t
являются немного необычными, поскольку стандарт говорит только о том, что они являются арифметическим типом, способным представлять времена. (В принципе, они могут быть сложными типами, но я бы сказал, игнорируя эту возможность, стоит риск.)
В большинстве других случаев вы, вероятно, знаете, подписан ли данный тип, без знака или с плавающей запятой, и вы можете просто преобразовать его в самый широкий тип такого типа.
Обратите внимание, что, если вы не знаете, как представлен time_t
, вы, вероятно, не поймете вывод printf
(например, 1379375215
) либо, если только ваша цель - понять это.
(Если вы программировали на С++, а не C, std::cout << t << "\n";
автоматически использовал бы перегруженный operator<<
.)
Если вы хотите получать данные, доступные для человека (например, Mon 2013-09-16 16:46:55 PDT
), вы захотите использовать одну из функций преобразования, объявленных в <time.h>
, например asctime()
или strftime()
.
Ответ 3
В стандарте C указано, что time_t
будет "реальным типом" (что означает целочисленный тип или тип с плавающей точкой, хотя на практике он всегда является целым типом).
С time_t
лучше всего отформатировать его с помощью strftime()
после анализа с помощью localtime()
или gmtime()
- это можно сделать портативно.
Непередаваемо, вам нужно определить каким-то механизмом, что является правильным спецификатором формата. Вы можете использовать PRI_[Xxodi]_time
и SCN_[Xxodi]_time
или что-то подобное как нестандартное, но близкое к стандарту (без портирования зарезервированного пространства имен - это имена, начинающиеся с PRI или SCN, за которыми следует строчная буква или X). Вы используете какой-то механизм, чтобы указать, что... инкапсулирование непортативной информации в одном месте.
Ответ 4
Вы можете использовать difftime()
для получения double
:
time_t t = time(NULL);
printf("seconds 1970->now: %.f\n", difftime(t, (time_t) 0));
Это просто, и я думаю, что он переносимый.