Почему difftime() приводит к разным результатам при использовании указателя mktime и не указателя?
Я пытаюсь использовать
difftime(time_t end, time_t mktime(start) )
рассчитать разницу между двумя разными временами двумя разными способами. Просто ради любопытства. И я обнаружил, что это приводит к различным результатам, неудачам и успехам. Я не знаю, почему это произошло?
Почему это приводит к различным результатам в двух случаях следующим образом?
// Failure Case 1 when execution, segmentation fault
time_t end;
time(&end);
struct tm * start; // defining a pointer
start->tm_hour = 0;
start->tm_min = 0;
start->tm_sec = 0;
start->tm_year = 114;
start->tm_mon = 6;
start->tm_mday = 29;
double second = difftime(end, mktime(start) ); // where problem come from!
// Success Case 2, with expected result
time_t end;
time(&end);
struct tm start; // defining a non-pointer
start.tm_hour = 0;
start.tm_min = 0;
start.tm_sec = 0;
start.tm_year = 114;
start.tm_mon = 6;
start.tm_mday = 29;
double second = difftime(end, mktime( &start) );
1 ответ
Исходный случай 1 не выделяет память, и оба случая не очищают ВСЕ поля в tm
структура, которая может потребоваться для получения правильного результата (и, безусловно, является "хорошей практикой").
Чтобы решить Случай 1 в C, лучшее решение состоит в том, чтобы использовать calloc
:
struct tm *start = calloc(1, sizeof(struct tm));
start->tm_year = 114;
start->tm_mon = 6;
start->tm_mday = 29;
а потом, когда вам больше не нужен start
ценность, использование
free(start);
(Обратите внимание, что поскольку структура заполнена нулями, вам больше не нужно вручную устанавливать часы, минуты, секунды)
В C++ вы бы использовали new
вместо:
tm *start = new tm();
...
// After it is finished.
delete start
Пустая скобка в tm()
делает его "заполненным нулевыми значениями" после выделения фактической памяти.
Вариант "Случай 2" является предпочтительным, поскольку он выделяет start
переменная в стеке.
Случай 1 несколько плохой, так как выделение памяти для небольших структур данных (маленький обычно означает что-то меньше, чем около 1 КБ, но это зависит от реальной среды выполнения, часы с 64 КБ ОЗУ могут иметь более строгие требования, чем настольный компьютер с 16 ГБ ОЗУ и мобильный телефон будет где-то посередине, в зависимости от того, что это за телефон). Есть по крайней мере две причины, чтобы избежать "маленьких" распределений памяти:
- Это занимает больше памяти, так как все известные распределители используют НЕКОТОРЫЕ дополнительные памяти, чтобы отслеживать фактический "кусок" выделенной памяти.
- Это занимает дополнительное время, потому что
new
или жеcalloc
намного сложнее, чем выделение в стеке (на типичных машинах выделение пространства в стеке занимает 1-2 инструкции выше и выше той же функции без каких-либо переменных вообще, где вызовnew
или же{c,m}alloc
может быть полдюжины только для вызова и то же самое снова дляdelete
или жеfree
и от нескольких десятков до нескольких тысяч инструкций внутри этих библиотечных функций - сколько времени занимает код, во многом зависит от того, как он реализован, и от того, имеется ли во время выполнения некоторая "доступная память", или требуется вызов в ОС, чтобы "получить еще немного" память "так же). И, конечно же, вам нужно следить за распределением, а не "просачивать" его. [Для этого тоже есть C++ решения, но я уже написал достаточно в этом ответе, чтобы было трудно следовать]
Для случая 2 вы можете использовать:
struct tm start = {};
(И опять же, вам не нужно устанавливать нулевые значения для часа, минут и секунд)
В C++ правильно опускать struct
, поскольку struct tm { ... };
объявление в соответствующем заголовочном файле делает имя tm
представлять структуру в любом случае - это относится ко всем struct
а также class
Имена - единственное исключение, если одно и то же имя используется по-другому, например, есть функция или переменная tm
в том же контексте - в этом случае компилятор выдаст сообщение об ошибке "не понимаю, что вы подразумеваете под tm
здесь " [точная формулировка зависит от того, какой компилятор используется].
Так как оригинальный вопрос определяет ОБА С и С ++, я попытался объяснить