Подтвердить что ты не робот

Спецификаторы формата для типов, определенных для реализации, таких как time_t

Я хочу сделать свой код более независимым от платформы/реализации. Я не знаю, как будет реализован time_t, как на платформе, когда код компилируется. Как узнать тип t, чтобы определить, какой спецификатор формата использовать?

...
time_t t = time(NULL);
printf("%s", t);
...
4b9b3361

Ответ 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));

Это просто, и я думаю, что он переносимый.