ctime_r 在 docker 中失败

ctime_r failed in docker

我在 docker 中有一个应用程序,它是多线程的。我的转移时间代码如下。

FILE *fp = NULL;
char buf[256] = {0};
char filename[64] = {0};
long timestamp;
char status[16] = {0};
char tbuf[26] = {0};


fp = popen(cmd, "r");
if (fp) {
    while (fscanf(fp, "%s %d %s", filename, &timestamp, status) != EOF) {
        char *ts = ctime_r(&timestamp, tbuf);
        if (ts) {
            ts[strlen(ts)-1] = '[=12=]';
            sprintf(buf, "%-32s%-32s%-8s", filename, ts, status);
        } else {
            sprintf(buf, "%-32s%-32s%-8s", filename, "Miss", status);
        }
    }
    pclose(fp);
}

但是tbuf的内容是"Sat Oct 29 21:37:05 44614",ts是NULL

我认为时间戳是一个有效值。但为什么失败了?

why it failed?

OP 后来添加了代码并报告了

启用警告后,我的编译器也会发出警告。

warning: format '%d' expects argument of type 'int *', but argument 4 has type 'long int *'


从文本文件中读取 time_t 很棘手。范围、纪元、数据类型属性都在起作用。此外,作为文件中的文本化数据,属性可能与编写它的系统不同。请注意 time_t.

没有 fscanf() 说明符

现在,让我们假设文本时间戳只是数字并且对应于一个整数 time_t,即使我们不知道整数类型的细节。更高级的技术不需要这些假设。

使用可用的最宽符号类型读取时间戳,例如 intmax_t(或在 C99 之前的系统上为 long)。一些范围检查是值得的。我还建议使用相同的宽字体来编写 time_t

注意:最好将 fscanf() return 值与一个预期值 (3) 进行比较,而不是仅与各种意外值(EOF、0、1、2)中的一个进行比较。对字符串输入使用宽度限制。

char filename[64] = {0};
char status[16] = {0};
// long timestamp;

// while (fscanf(fp, "%s %d %s", filename, &timestamp, status) != EOF) {
intmax_t timestamp_big;   
while (fscanf(fp, "%63s %jd %15s", filename, &timestamp_big, status) == 3) {
  time_t timestamp = (time_t) timestamp_big;
  if (timestamp != timestamp_big) Handle_OutOfRangeError();
  ...

long timestamp 容易出现 Y2038 bug.