【问题标题】:How do I compare two timestamps in C?如何比较 C 中的两个时间戳?
【发布时间】:2009-12-07 05:49:55
【问题描述】:

我正在编写一个套接字程序,它为两个输入套接字维护 FIFO 队列。在决定服务哪个队列时,程序会从每个队列中提取最新的时间戳。

我需要一个可靠的方法来比较两个timeval 结构。我尝试使用timercmp(),但我的 gcc 版本不支持它,并且文档指出该函数不符合 POSIX。

我该怎么办?

【问题讨论】:

    标签: c sockets timestamp timeval


    【解决方案1】:

    timercmp() 只是 libc (sys/time.h) 中的一个宏:

    # define timercmp(a, b, CMP)                                                  \
      (((a)->tv_sec == (b)->tv_sec) ?                                             \
       ((a)->tv_usec CMP (b)->tv_usec) :                                          \
       ((a)->tv_sec CMP (b)->tv_sec))
    

    如果你需要timersub():

    # define timersub(a, b, result)                                               \
      do {                                                                        \
        (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                             \
        (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                          \
        if ((result)->tv_usec < 0) {                                              \
          --(result)->tv_sec;                                                     \
          (result)->tv_usec += 1000000;                                           \
        }                                                                         \
      } while (0)
    

    【讨论】:

    • 如果在 Linux 上编译,需要定义 _BSD_SOURCE 宏。
    【解决方案2】:

    谷歌搜索timevalthis first result。从该页面:

    通常需要减去 struct timeval 或 struct timespec 类型的两个值。这是执行此操作的最佳方法。它甚至适用于 tv_sec 成员具有无符号类型的某些特殊操作系统。

     /* Subtract the `struct timeval' values X and Y,
        storing the result in RESULT.
        Return 1 if the difference is negative, otherwise 0.  */
    
     int
     timeval_subtract (result, x, y)
          struct timeval *result, *x, *y;
     {
       /* Perform the carry for the later subtraction by updating y. */
       if (x->tv_usec < y->tv_usec) {
         int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
         y->tv_usec -= 1000000 * nsec;
         y->tv_sec += nsec;
       }
       if (x->tv_usec - y->tv_usec > 1000000) {
         int nsec = (x->tv_usec - y->tv_usec) / 1000000;
         y->tv_usec += 1000000 * nsec;
         y->tv_sec -= nsec;
       }
    
       /* Compute the time remaining to wait.
          tv_usec is certainly positive. */
       result->tv_sec = x->tv_sec - y->tv_sec;
       result->tv_usec = x->tv_usec - y->tv_usec;
    
       /* Return 1 if result is negative. */
       return x->tv_sec < y->tv_sec;
     }
    

    【讨论】:

    • 感谢您的提示,但我已经在使用代码了。事实上,我刚刚意识到我的问题是什么。感谢您检查 Google,这可能是我作为答案发布的第一件事。 =)
    • 澄清一下,我意识到时间值被初始化为具有tv_sectv_usec 值0。使用gettimeofday() 正确初始化队列解决了这个问题。感谢您的支持。 =)
    • 2AShelly,我要补充一点,恕我直言,最好按照以下方式更改第二个条件x-&gt;tv_usec - y-&gt;tv_usec &gt;= 1000000,以便将5/1000000 之类的时间转换为6/0
    • 为了避免其他人遇到我做的同样的错误,请注意调用此函数有 50-50 的机会修改 y 参数,从而导致您传入的 timeval 被修改。
    • @AShelly : Wudn't ` int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;` 因为 y->tv_usec 和 x,这个操作总是输入 nsec = 1 ->tv_usec 小于 1 e6
    【解决方案3】:

    这略有不同,但我认为清楚地说明了所涉及的逻辑。 我正在用 C 编写一些 MSP430 代码,并且有一个与 timeval 非常相似的时间戳结构,但使用的是 nsecs 而不是 usecs。

    这段代码保持一切积极,所以无符号整数可以正常工作,并避免溢出(我认为)。它也不会修改传入的时间戳/时间值,当然结果除外。

    typedef struct timestamp {
        int32_t secs;
        int32_t nsecs;
    } timestamp_t;
    
    int timestamp_sub(timestamp_t * x, timestamp_t * y, timestamp_t * result){
        // returns 1 if difference is negative, 0 otherwise
        // result is the absolute value of the difference between x and y
        negative = 0;
        if( x->secs > y->secs ){
            if( x->nsecs > y->nsecs ){
                result->secs = x->secs - y->secs;
                result->nsecs = x->nsecs - y->nsecs;
            }else{
                result->secs = x->secs - y->secs - 1;
                result->nsecs = (1000*1000*1000) - y->nsecs + x->nsecs;
            }
        }else{
            if( x->secs == y->secs ){
                result->secs = 0;
                if( x->nsecs > y->nsecs ){
                    result->nsecs = x->nsecs - y->nsecs;
                }else{
                    negative = 1;
                    result->nsecs = y->nsecs - x->nsecs;
                }
            }else{
                negative = 1;
                if( x->nsecs > y->nsecs ){
                    result->secs = y->secs - x->secs - 1;
                    result->nsecs = (1000*1000*1000) - x->nsecs + y->nsecs;
                }else{
                    result->secs = y->secs - x->secs;
                    result->nsecs = y->nsecs - x->nsecs;
                }
            }
        }
        return negative;
    }
    

    【讨论】:

    • 你最好使用整数1000000000(或者1000*1000*1000,如果你愿意的话)而不是浮点数1e9,因为前者可能更有效。
    【解决方案4】:

    为了查看时间间隔,我刚刚做了这个。它以字符串形式返回时间值,您可以将其打印或发送到文本文件:

    char *tv2str(struct timeval *intv) {
      static char ans[200];
      snprintf(ans,200,"%u.%u",(unsigned int)intv->tv_sec, \
        (unsigned int) intv->tv_usec);
      return ans;
    }
    

    像这样使用:

    printf("nowtv: %s\n",tv2str(&nowtv));
    

    现在电视:1568407554.646623

    Timercmp() 似乎不能正常工作,所以我想通过实际查看一些值来检查它。

    【讨论】:

      猜你喜欢
      • 2021-04-25
      • 2012-02-04
      • 1970-01-01
      • 2016-08-06
      • 2016-09-07
      • 2015-01-02
      • 2019-02-27
      • 2017-07-10
      • 1970-01-01
      相关资源
      最近更新 更多