为什么在使用mktime处理指针和非指针时,difftime()会导致不同的结果?

时间:2022-10-16 08:35:03

I try to use

我试着使用

    difftime(time_t end, time_t mktime(start) ) 

to calculate the difference between two different time in two different ways. Just for curiosity!And I found it results in different results, failure and success. I don't know why it happened?

用两种不同的方法计算两种不同时间的差值。只是为了好奇心!我发现它导致不同的结果,成功和失败。我不知道为什么会这样?

Why does it result in different results in two cases as following?

为什么两种情况下会导致不同的结果?

    // 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


3  

The original case 1 doesn't allocate memory, and both cases do not clear ALL the fields in the tm structure, which may be required to get the correct result (and certainly is a "good practice").

最初的案例1不分配内存,而且这两种情况都不清楚tm结构中的所有字段,这可能需要得到正确的结果(当然这是一个“良好的实践”)。

To solve Case 1 in C, the best solution is to use calloc:

为了解决C的案例1,最好的解决方案是使用calloc:

struct tm *start = calloc(1, sizeof(struct tm)); 

start->tm_year = 114;
start->tm_mon  = 6;
start->tm_mday = 29;

and then when you no longer need the start value, use

当你不再需要开始值时,使用。

free(start);

(Note that since the structure is filled with zeros, you no longer need to manually set hour, min, sec)

(注意,由于结构中填充了0,所以不再需要手动设置小时、分钟、秒)

In C++, you'd use new instead:

在c++中,您将使用new:

tm *start = new tm(); 
...
// After it is finished. 
delete start

The empty parenthesis in tm() makes it "fill with zero values" after allocating the actual memory.

tm()中的空圆括号使它在分配实际内存后“填充零值”。

The "Case 2" variant is preferred, since it allocates the start variable on the stack.

“案例2”的变体是首选,因为它在堆栈上分配开始变量。

Case 1 are somewhat bad, since allocating memory for small data structures (small typically means anything smaller than around 1KB, but it depends on the actual runtime environment, a watch with 64KB of RAM may have stricter requirements than a desktop machine with 16GB of RAM, and a mobile phone would be somewhere in between those, somewhat depending on what kind of phone it is). There are at least two reasons to avoid "small" memory allocations:

案例1有些不好,因为对小型数据结构分配内存(小通常意味着任何小于1 kb左右,但这取决于实际的运行时环境,手表和64 kb的RAM可能有更严格的要求比16 gb的RAM,桌面机和手机将介于两者之间,某种程度上取决于什么样的电话)。避免“小”内存分配至少有两个原因:

  1. It takes more memory, since all known allocators use SOME extra memory to keep track of the actual "lump" of memory allocated.
  2. 它需要更多的内存,因为所有已知的分配器都使用一些额外的内存来跟踪分配的实际“块”。
  3. It takes extra time because new or calloc are much more complex than the allocation on the stack (in typical machines, allocating space on the stack takes 1-2 instructions above and beyond the same function with no variables at all, where a call to new or {c,m}alloc can be half a dozen just for the call and the same again for delete or free, and several dozen to a few thousand instructions inside those library functions - how long the code is depends largely on how it is implemented, and whether the runtime has some "memory available" or a call into the OS is required to "get some more memory" as well). And of course, you need to keep track of the allocation and not "leak" it. [There are C++ solutions to do that too, but I've written enough in this answer already to make it hard to follow]
  4. 需要额外的时间,因为新的或calloc复杂得多比分配在堆栈上(在典型的机器,在堆栈上分配空间需要1 - 2说明超出相同的功能没有变量,调用新的或{ c、m } alloc可以半打为再次调用和相同的删除或免费的,和几十到几千指令在这些库函数,代码是多长时间在很大程度上取决于如何实现的,并且运行时是否有一些“可用内存”或者调用操作系统来“获得更多的内存”。当然,您需要跟踪分配,而不是“泄漏”它。(也有c++的解决方案,但是我已经在这个答案中写了足够多的内容了)

For case 2 you can use:

对于案例2,你可以使用:

struct tm start = {}; 

(And again, you don't need to set zero-values for hour, min and sec)

(同样,您不需要设置小时、分钟和秒的零值)

In C++ it is correct to omit struct, since struct tm { ... }; declaration in the relevant header file makes the name tm represent the structure anyway - this applies for all struct and class names - only exception is if the same name is used in a different way, e.g. there's a function or variable called tm in the same context - in which case the compiler will give some error saying "don't understand what you mean by tm here" [exact wording varies depending on which compiler is used].

在c++中省略struct是正确的,因为struct tm{…};声明在相关头文件的名字tm代表结构无论如何——这适用于所有结构体和类名——唯一的例外是如果使用相同的名称在不同的方式,例如有一个函数或变量叫做tm在同一上下文——在这种情况下,编译器会给一些错误说”不明白你意思tm”(确切的措辞变化取决于编译器使用)。

Since the original question specifies BOTH C and C++, I've tried to explain

因为最初的问题指定了C和c++,所以我试着解释。

#1


3  

The original case 1 doesn't allocate memory, and both cases do not clear ALL the fields in the tm structure, which may be required to get the correct result (and certainly is a "good practice").

最初的案例1不分配内存,而且这两种情况都不清楚tm结构中的所有字段,这可能需要得到正确的结果(当然这是一个“良好的实践”)。

To solve Case 1 in C, the best solution is to use calloc:

为了解决C的案例1,最好的解决方案是使用calloc:

struct tm *start = calloc(1, sizeof(struct tm)); 

start->tm_year = 114;
start->tm_mon  = 6;
start->tm_mday = 29;

and then when you no longer need the start value, use

当你不再需要开始值时,使用。

free(start);

(Note that since the structure is filled with zeros, you no longer need to manually set hour, min, sec)

(注意,由于结构中填充了0,所以不再需要手动设置小时、分钟、秒)

In C++, you'd use new instead:

在c++中,您将使用new:

tm *start = new tm(); 
...
// After it is finished. 
delete start

The empty parenthesis in tm() makes it "fill with zero values" after allocating the actual memory.

tm()中的空圆括号使它在分配实际内存后“填充零值”。

The "Case 2" variant is preferred, since it allocates the start variable on the stack.

“案例2”的变体是首选,因为它在堆栈上分配开始变量。

Case 1 are somewhat bad, since allocating memory for small data structures (small typically means anything smaller than around 1KB, but it depends on the actual runtime environment, a watch with 64KB of RAM may have stricter requirements than a desktop machine with 16GB of RAM, and a mobile phone would be somewhere in between those, somewhat depending on what kind of phone it is). There are at least two reasons to avoid "small" memory allocations:

案例1有些不好,因为对小型数据结构分配内存(小通常意味着任何小于1 kb左右,但这取决于实际的运行时环境,手表和64 kb的RAM可能有更严格的要求比16 gb的RAM,桌面机和手机将介于两者之间,某种程度上取决于什么样的电话)。避免“小”内存分配至少有两个原因:

  1. It takes more memory, since all known allocators use SOME extra memory to keep track of the actual "lump" of memory allocated.
  2. 它需要更多的内存,因为所有已知的分配器都使用一些额外的内存来跟踪分配的实际“块”。
  3. It takes extra time because new or calloc are much more complex than the allocation on the stack (in typical machines, allocating space on the stack takes 1-2 instructions above and beyond the same function with no variables at all, where a call to new or {c,m}alloc can be half a dozen just for the call and the same again for delete or free, and several dozen to a few thousand instructions inside those library functions - how long the code is depends largely on how it is implemented, and whether the runtime has some "memory available" or a call into the OS is required to "get some more memory" as well). And of course, you need to keep track of the allocation and not "leak" it. [There are C++ solutions to do that too, but I've written enough in this answer already to make it hard to follow]
  4. 需要额外的时间,因为新的或calloc复杂得多比分配在堆栈上(在典型的机器,在堆栈上分配空间需要1 - 2说明超出相同的功能没有变量,调用新的或{ c、m } alloc可以半打为再次调用和相同的删除或免费的,和几十到几千指令在这些库函数,代码是多长时间在很大程度上取决于如何实现的,并且运行时是否有一些“可用内存”或者调用操作系统来“获得更多的内存”。当然,您需要跟踪分配,而不是“泄漏”它。(也有c++的解决方案,但是我已经在这个答案中写了足够多的内容了)

For case 2 you can use:

对于案例2,你可以使用:

struct tm start = {}; 

(And again, you don't need to set zero-values for hour, min and sec)

(同样,您不需要设置小时、分钟和秒的零值)

In C++ it is correct to omit struct, since struct tm { ... }; declaration in the relevant header file makes the name tm represent the structure anyway - this applies for all struct and class names - only exception is if the same name is used in a different way, e.g. there's a function or variable called tm in the same context - in which case the compiler will give some error saying "don't understand what you mean by tm here" [exact wording varies depending on which compiler is used].

在c++中省略struct是正确的,因为struct tm{…};声明在相关头文件的名字tm代表结构无论如何——这适用于所有结构体和类名——唯一的例外是如果使用相同的名称在不同的方式,例如有一个函数或变量叫做tm在同一上下文——在这种情况下,编译器会给一些错误说”不明白你意思tm”(确切的措辞变化取决于编译器使用)。

Since the original question specifies BOTH C and C++, I've tried to explain

因为最初的问题指定了C和c++,所以我试着解释。