【问题标题】:C time.h wrap aroundC time.h 环绕
【发布时间】:2017-12-12 03:13:36
【问题描述】:

我想将最大可能时间分配给 time_t 变量,然后将其转换为字符串并打印出结果。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>

int main()
{
    time_t maxTime;
    maxTime= LONG_LONG_MAX;
    char *strOfMaxTime;
    *strOfMaxTime = ctime(maxTime);

    printf("%s",strOfMaxTime);

    return 0;
}

【问题讨论】:

  • 这是一个课堂作业吗(即你需要以某种方式去做)?我会相应地回答这个问题。
  • 我正在阅读 Linden 的《Expert C Programming , Deep C Secrets》一书。所以你的答案是否定的。我只是想自学。
  • 这将是一个 64 位的 int,所以 maxTime 应该已经设置在 maxTime=LONG_LONG_MAX
  • 是的。我也是那么想的。我分配的和你写的完全一样。但是我有一个运行时错误,一旦我编译并运行代码,程序就会停止执行。
  • 注意:C 没有将time_t 指定为long long 甚至整数。 maxTime= LONG_LONG_MAX; 是一个猜测 - 可能是对的 - 可能不是。

标签: c pointers char time.h


【解决方案1】:

OP 的代码错误地使用了char *ctime(const time_t *timer)

time_t maxTime;
char *strOfMaxTime;
// *strOfMaxTime = ctime(maxTime);
strOfMaxTime = ctime(&maxTime);

然而,简单地分配maxTime= LONG_LONG_MAX; 并不是确定系统可以处理的最长时间的正确方法。

以下是一种试错法 - 可能存在各种实施限制。当time_t 超出范围时,localtime() 返回NULL

#include <stdio.h>
#include <time.h>

time_t max_time() {
  time_t t0, t1;
  time_t delta = 1;
  time(&t0);    // now
  while (t0 != -1) {
    t1 = t0 + delta;
    if (localtime(&t1) == NULL) {  // If conversion fail, quit doubling.
      break;
    }
    delta *= 2; // 2x for  the next increment.
    t0 = t1;
  }
  while (delta) {
    t1 = t0 + delta;
    if (localtime(&t1) != NULL) { // if succeeds, update t0
      t0 = t1;
    }
    delta /= 2; // try smaller and smaller deltas.
  }
  printf("%s %lld\n", ctime(&t0), (long long) t0);
  return t0;
}

int main(void) {
  max_time();
  return 0;
}

输出(请注意,17:59:59 取决于时区,2,147,483,647 年是最大的 32 位有符号整数。YMMV。)

Tue Dec 31 17:59:59 2147483647
 67767976233532799

【讨论】:

  • 2038 年 1 月 19 日星期二 06:14:07 是我使用 INT_MAX 得到的输出。我正在检查你所说的。谢谢你的信息。
  • @user3524633 当您尝试使用 INT_MAX + 1LL 之类的值时,您的系统报告时间戳是否超过了 2038 年 1 月 19 日星期二 06:14:07?
  • 我会尽快坐在我的电脑前尝试。你激发了我的好奇心。
  • 计算说明:ctime(timer) 等价于asctime(localtime(timer))locatime() 的结果指向一个 struct tm,其中包括一个 tm_year 成员。该成员必须是类型int。所以INT_MAX * secs/year(大约 32,000,000 秒)可能是秒的上限。 如果 time_t 是秒计数,并且是 32 位 int,那么对于成功的 ctime(),大约 68,000,000,000,000,000 的值是 time_t 的合理上限。
【解决方案2】:

来自C Standards#7.27.1p4

clock_t 和 time_t 中可表示的时间范围和精度是实现定义的

首先,您需要解决程序中的问题。以下语句在编译时一定会出错:

*strOfMaxTime = ctime(maxTime);

将其更改为:

strOfMaxTime = ctime(&maxTime);

您可以使用perror() 获取给定输入的错误消息 - LONG_LONG_MAX,如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#include <errno.h>

int main()
{
    time_t maxTime;
    maxTime= LONG_LONG_MAX;
    char *strOfMaxTime;
    strOfMaxTime = ctime(&maxTime);
    if (errno != 0)
       perror ("Error");
    else
       printf("%d,%s",errno, strOfMaxTime);

    return 0;
}

在我的设置中,我得到了这个输出:

Error: Value too large to be stored in data type

确实,LONG_LONG_MAX 是无效输入。

正如标准提到的time_t 的范围是实现定义的,所以如果我给UINT_MAX 我得到输出:

0,Sun Feb  7 11:58:15 2106

【讨论】:

  • 2038 年 1 月 19 日星期二 06:14:07 是我正在使用 INT_MAX 的输出。感谢您提供的信息。我在上面
  • 请注意,这取决于 time_t 是 32 位类型(它似乎在您的系统上)还是 64 位类型(在许多其他系统上都有)。例如,在运行 macOS High Sierra 的 Mac 上,sizeof(time_t) == 8。但是,它不会将 LONG_MAX 转换为 struct tm;在获得转换之前,您必须除以 256,它表示:T(max) = 36028797018963967 = 1141709097-06-13 06:26:07 - after dividing 9223372036854775807 by 2^8
  • @jonathanleffler 你是通过尝试失败找到 2^8 还是背后有规则。如果是这样,我想学习它。感谢您提供的所有信息。在这篇文章中,每个人都非常乐于助人和有启发性。
  • 我使用了反复试验。我将 time_t 值设置为 LONG_MAX 并且它失败了,所以我除以 2 直到它通过。这是8次迭代。实际上,我的代码很像 TonyBanswer,除了我使用 `strftime 来获取 YYYYYYYYYY-MM-DD HH:MM:SS 格式(年份为 10 位)。总的来说,我不认为我会担心 Y10B(十亿)问题(除了它是 Y11.4B,给或需要几百万年)。
【解决方案3】:

这是错误的:

*strOfMaxTime = ctime(maxTime);

这会尝试将ctime(一个指向字符的指针)的返回值分配给*strOfMaxTime一个字符。

改为调用:

strOfMaxTime = ctime(&maxTime);

然后检查strOfMaxTime的返回值,如果ctime转换失败maxTime可能为NULL

【讨论】:

  • 还是同样的问题。我第一次遇到问题时尝试过。
  • 看看上面的cmets里@chux是怎么说的。
【解决方案4】:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>

int main()
{
    time_t maxTime;
    maxTime = INT_MAX;
    char *strOfMaxTime = ctime(&maxTime);

    printf("%s",strOfMaxTime);

    return 0;
}

最大年份是 2038 年,这被称为 2038 年问题: https://en.wikipedia.org/wiki/Year_2038_problem

【讨论】:

  • 代码怎么知道INT_MAXtime_t的最大值?
【解决方案5】:

在其他帖子中指出了许多错误(将ctime() 的输出分配给*strOfMaxTimeLONG_LONG_MAX 等)。在我的 64 位 Ubuntu 16.04 Linux 系统上,time_t 定义为 long intlong int 定义为 8 个字节,long long int 也是如此。但是将LLONG_MAX 分配给maxTime 仍然会导致ctime() 失败。因此,我修改了您的代码以获取有效值上限 ctime() 将接受的范围。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <limits.h>

int main()
{
    time_t maxTime;

    maxTime= LONG_MAX;

    char *strOfMaxTime;

    strOfMaxTime = ctime(&maxTime);

    while( strOfMaxTime == NULL )
    {
        perror("ctime error");
        printf("%ld div by 2\n", maxTime);
        maxTime /= 2;
        strOfMaxTime = ctime(&maxTime);
    }
    printf("%s\n",strOfMaxTime);

    return 0;
}

运行它会产生以下输出:

ctime error: Invalid argument
9223372036854775807 div by 2
ctime error: Invalid argument
4611686018427387903 div by 2
ctime error: Invalid argument
2305843009213693951 div by 2
ctime error: Invalid argument
1152921504606846975 div by 2
ctime error: Invalid argument
576460752303423487 div by 2
ctime error: Invalid argument
288230376151711743 div by 2
ctime error: Invalid argument
144115188075855871 div by 2
ctime error: Invalid argument
72057594037927935 div by 2
Sat Jun 12 22:26:07 1141709097

【讨论】:

  • 为什么 ctime 不转换年份字段但不给出分配错误。顺便感谢您的指导性回答。
猜你喜欢
  • 2012-10-01
  • 2015-08-18
  • 1970-01-01
  • 1970-01-01
  • 2023-02-01
  • 1970-01-01
  • 2013-12-24
  • 2019-08-16
  • 1970-01-01
相关资源
最近更新 更多