Por que difftime() resulta em resultados diferentes ao usar ponteiro e não ponteiro de manipulação mktime?
Pergunta
eu tento usar
difftime(time_t end, time_t mktime(start) )
para calcular a diferença entre dois tempos diferentes de duas maneiras diferentes.Só por curiosidade! E descobri que resulta em resultados diferentes, fracasso e sucesso.Eu não sei por que isso aconteceu?
Por que isso resulta em resultados diferentes em dois casos como segue?
// 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) );
Solução
O caso original 1 não aloca memória e ambos os casos não limpam TODOS os campos do tm
estrutura, que pode ser necessária para obter o resultado correto (e certamente é uma "boa prática").
Para resolver o Caso 1 em C, a melhor solução é usar calloc
:
struct tm *start = calloc(1, sizeof(struct tm));
start->tm_year = 114;
start->tm_mon = 6;
start->tm_mday = 29;
e então quando você não precisar mais do start
valor, uso
free(start);
(Observe que como a estrutura é preenchida com zeros, você não precisa mais definir manualmente hora, min, seg)
Em C++, você usaria new
em vez de:
tm *start = new tm();
...
// After it is finished.
delete start
O parêntese vazio em tm()
faz com que ele seja "preenchido com valores zero" após alocar a memória real.
A variante "Caso 2" é preferida, pois aloca o start
variável na pilha.
O caso 1 é um tanto ruim, pois alocar memória para pequenas estruturas de dados (pequeno normalmente significa algo menor que cerca de 1 KB, mas depende do ambiente de execução real, um relógio com 64 KB de RAM pode ter requisitos mais rígidos do que uma máquina desktop com 16 GB de RAM , e um telefone celular estaria em algum lugar entre eles, dependendo do tipo de telefone).Existem pelo menos dois motivos para evitar alocações de memória "pequenas":
- É preciso mais memória, já que todos os alocadores conhecidos usam ALGUMA memória extra para controlar o "pedaço" real de memória alocada.
- Leva mais tempo porque
new
oucalloc
são muito mais complexos do que a alocação na pilha (em máquinas típicas, a alocação de espaço na pilha leva de 1 a 2 instruções acima e além da mesma função, sem nenhuma variável, onde uma chamada paranew
ou{c,m}alloc
pode ser meia dúzia apenas para a ligação e o mesmo novamente paradelete
oufree
, e várias dezenas a alguns milhares de instruções dentro dessas funções de biblioteca - a duração do código depende muito de como ele é implementado e se o tempo de execução tem alguma "memória disponível" ou se uma chamada ao sistema operacional é necessária para "obter mais memória" também).E, claro, você precisa acompanhar a alocação e não “vazá-la”.[Existem soluções C++ para fazer isso também, mas já escrevi o suficiente nesta resposta para dificultar o acompanhamento]
Para o caso 2 você pode usar:
struct tm start = {};
(E novamente, você não precisa definir valores zero para hora, minuto e segundo)
Em C++ é correto omitir struct
, desde struct tm { ... };
declaração no arquivo de cabeçalho relevante torna o nome tm
representar a estrutura de qualquer maneira - isso se aplica a todos struct
e class
nomes - a única exceção é se o mesmo nome for usado de uma maneira diferente, por ex.existe uma função ou variável chamada tm
no mesmo contexto - nesse caso o compilador apresentará algum erro dizendo "não entendo o que você quer dizer com tm
aqui" [o texto exato varia dependendo de qual compilador é usado].
Como a pergunta original especifica AMBOS C e C++, tentei explicar