【问题标题】:Why does difftime() result in different result when using mktime handling pointer and non-pointer?为什么使用 mktime 处理指针和非指针时 difftime() 会导致不同的结果?
【发布时间】:2014-07-30 23:07:39
【问题描述】:

我尝试使用

    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) );

【问题讨论】:

  • 您正在通过一个不确定的指针 (struct tm *start;) 分配数据,这样做会调用 未定义的行为
  • 你忘记为 *start 分配内存
  • @TomásBadan 这种情况下如何分配内存?
  • 可以使用malloc:start = malloc(sizeof(*start));
  • 即便如此,由于tm 结构中的未初始化字段,您可能会得到不同的结果。例如struct tm start = {};struct 这个词在 C++ 中是可选的,在 C 中是必需的)或 tm *start = new tm(); [C++] 或 struct tm *start = calloc(1, sizeof(tm)); [C]

标签: c++ c mktime time.h


【解决方案1】:

最初的情况 1 不分配内存,并且两种情况都没有清除 tm 结构中的所有字段,这可能是获得正确结果所必需的(当然是一个“好习惯”)。

要解决C中的案例1,最好的解决方案是使用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 有点糟糕,因为为小型数据结构分配内存(小型通常意味着小于 1KB 左右,但这取决于实际运行时环境,具有 64KB RAM 的手表可能比具有16GB RAM,而手机介于两者之间,这在某种程度上取决于它是什么类型的手机)。避免“小”内存分配至少有两个原因:

  1. 它需要更多内存,因为所有已知的分配器都使用一些额外的内存来跟踪实际分配的内存“块”。
  2. 这需要额外的时间,因为 newcalloc 比堆栈上的分配要复杂得多(在典型的机器中,在堆栈上分配空间需要 1-2 条指令,超过同一函数,而在全部,其中对new{c,m}alloc 的调用可能是六个,对于deletefree 的调用可能是六次,对于这些库函数中的几十到几千条指令 - 多长时间代码很大程度上取决于它是如何实现的,以及运行时是否有一些“可用内存”或者是否需要调用操作系统来“获得更多内存”)。当然,您需要跟踪分配而不是“泄漏”它。 [也有 C++ 解决方案可以做到这一点,但我已经在这个答案中写了足够多的内容,很难理解]

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

struct tm start = {}; 

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

在 C++ 中,省略 struct 是正确的,因为相关头文件中的 struct tm { ... }; 声明使得名称 tm 无论如何都代表结构 - 这适用于所有 structclass 名称 - 唯一例外是如果以不同的方式使用相同的名称,例如在相同的上下文中有一个名为 tm 的函数或变量 - 在这种情况下,编译器会给出一些错误,说“这里不理解 tm 的意思”[确切的措辞因使用的编译器而异]。

由于最初的问题指定了 C 和 C++,我试图解释一下

【讨论】:

  • 强烈推荐 C++ 中的第二个变体。尽可能避免使用新的。那你不能忘记删除。
  • @MatsPeersson 你的回答很清楚。非常感谢。但是,无论哪种方式,变量“start”都会在“second = difftime(end, mktime(&start));”行之后增加 1 小时,我不知道为什么。
  • @MatsPeersson 我知道我的结果来自哪里。我从不为成员“tm_isdst”分配有意义的值。 mktime() 因此使用不确定的值,结果是未定义的行为。
猜你喜欢
  • 1970-01-01
  • 2012-07-23
  • 1970-01-01
  • 2020-10-28
  • 2021-12-18
  • 1970-01-01
  • 2020-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多