在编译时获取纪元时间

Posted

技术标签:

【中文标题】在编译时获取纪元时间【英文标题】:Getting Epoch Time at Compile Time 【发布时间】:2013-08-15 11:13:42 【问题描述】:

上下文:我正在编写一种重要的客户端-服务器 UDP 多播程序,我将其部署在一些无线节点上。部署的方法是我编写的一个脚本,它广播 ping 这些节点所在的网络,获取节点列表(基于 IP 地址),部署我的包并安装它。我注意到有时在部署时并未检测到所有节点,并且我正在开发的最新包没有安装。最终,在一个节点上运行的服务器可能比希望与服务器通信的客户端更老。因为服务器获取数据包,并根据该数据包中的条目分配内存,所以如果结构发生变化,服务器通常会在段错误中崩溃。作为一种解决方案,我正在考虑在客户端和服务器之间发送的数据包中实现版本号,这样如果服务器/客户端读取一个版本号不同的数据包(或者由于重组而成为垃圾)数据包),此数据包将被忽略,并更新日志,或将紧急数据包发送给原始发送者。

所以,我试图想出在编译时获取这个“版本号”的最佳方法,它可以作为#define 放在标头中。我查看了__time__ 预处理器宏,但这是字符串的形式。有没有办法在编译期间获取纪元时间,以便我可以将其位掩码为无符号整数(如果我正确考虑的话,它应该只在 136 年后翻转)?

对不起,如果我不清楚。

【问题讨论】:

当然,更好的解决方案是简单地将数据包的大小作为数据包的一部分发送到另一端。 您确定要在每次编译时更改版本吗?数据包结构似乎不太可能(对我作为一个不知情的观察者而言)不会随着每次编译而改变。版本更改似乎更像是一种有意识的努力,您偶尔会“手动”更改它。我只是好奇。 @MarkWilkins:是的,我也是这么想的。尤其是在开发过程中,每次重新编译代码时都必须分发新的可执行文件,这真的很烦人,这仅仅是因为对某些调试日志进行了小改动,或者诸如此类。 @MatsPetersson,我明白你在说什么,但我确实必须将可执行文件分发到至少一个节点,因为我做了一个微不足道的更改,比如调试日志记录。这与甚至 10 个节点之间的差异几乎没有。为什么不分发修复程序,无论我正在测试的所有节点有多小?我想,做这个版本号的事情只是更“自动”。我/可以/仅在更改数据包结构时手动更改数字,但如果我忘记了怎么办? 我在这种情况下使用的是,使用来自 CVS 的版本号。也许你的版本控制系统有类似的东西? 【参考方案1】:

这取决于你的构建系统,但如果你使用 gmake,你 可以做类似的事情:

CXX_TIME = -DBUILDTIME=$(shell python -c "import time; print( int( time.time() ) )" )

将此添加到您的其他编译器选项中,然后使用 在您的代码中添加宏 BUILDTIME

(这假设您已经在路径中安装了 Python。 如果没有,您可以安装它,或者执行类似的操作 您已安装的工具。)

【讨论】:

如果你不想使用python,你也可以用seddate写一个shell脚本。 只能使用$(shell date "+%s") 这正是我正在寻找的……我只是不知道你可以在 Makefile 中做到这一点(它们不是我真正的东西)。虽然我更喜欢@jxh 避免使用 Python 的方法。谢谢你:) @jxh 除了date 没有"%s" 格式说明符,至少根据Posix。某些特定平台可能支持它;例如,CygWin 确实如此,因此如果对不同平台的可移植性不是问题,这可能是首选解决方案。 (这里的“最佳”解决方案取决于上下文:它可能是 date、Python、Ruby 或您习惯用于编写脚本的任何其他工具的非便携式使用。我自己可能会提到 date 解决方案,有我知道这一点,但我在 Sun 机器上学习了 Unix,并使用 Posix 文档作为我的参考。) @JamesKanze:它似乎是一个 GNU 扩展,这可以解释为什么它适用于 CygWin。【参考方案2】:

您可以从__DATE__ 预处理器宏中获取纪元。

getCompileTimeEpoch() 函数下方,该函数又依赖于另外两个简单的辅助函数,它们返回月份编号和另一个将月份首字母缩写词转换为小写的函数。

让我感到困惑的是,GCC 开发人员如何引入了一个带有人类可读日期而不是纪元的宏,从中可以以最大的可靠性推导出有关日期的任何其他信息。

如果您需要将时间添加到纪元,您可以很容易地从 __TIME__ 宏中添加时间。

我选择了这个解决方案,因为它将所有内容都保留在代码中,并且不依赖于编译器选项。

char *tolowercase(char *letstr)
    int l;
    for(l=0;l<=strlen(letstr);l++)
        if(letstr[l]>=65 && letstr[l]<=92)
            letstr[l]=letstr[l]+32;
        
    
    return letstr;


int getMonFromAbbr(char *abbr)
    if (strlen(abbr) > 0)
        tolowercase(abbr);
    if ( strcmp(abbr, "jan") == 0 )
        return 0;
    if ( strcmp(abbr, "feb") == 0 )
        return 1;
    if ( strcmp(abbr, "mar") == 0 )
        return 2;
    if ( strcmp(abbr, "apr") == 0 )
        return 3;
    if ( strcmp(abbr, "may") == 0 )
        return 4;
    if ( strcmp(abbr, "jun") == 0 )
        return 5;
    if ( strcmp(abbr, "jul") == 0 )
        return 6;
    if ( strcmp(abbr, "aug") == 0 )
        return 7;
    if ( strcmp(abbr, "sep") == 0 )
        return 8;
    if ( strcmp(abbr, "oct") == 0 )
        return 9;
    if ( strcmp(abbr, "nov") == 0 )
        return 10;
    if ( strcmp(abbr, "dec") == 0 )
        return 11;
    return(-1);


// Convert from __DATE__ macro
uint64_t getCompileTimeEpoch()
    char date_macro[20]="";
    strcpy(date_macro, __DATE__);
    char *token;
    int yea=0;
    int mon=0;
    int day=0;
    token=strtok(date_macro, " ");
    if (token != NULL)
        mon=getMonFromAbbr(token);
        token=strtok(NULL, " ");
        if (token != NULL)
            day=atoi(token);
            token=strtok(NULL, " ");
            if (token != NULL)
                yea=atoi(token);
                struct tm t;
                time_t epoch_t;
                t.tm_year = yea-1900;    // Year - 1900
                t.tm_mon = mon;          // Month, where 0 = jan
                t.tm_mday = day;         // Day of the month
                t.tm_hour = 0;
                t.tm_min = 0;
                t.tm_sec = 0;
                t.tm_isdst = 0;         // Is DST on? 1 = yes, 0 = no, -1 = unknown
                epoch_t = mktime(&t);               
                return epoch_t;
                       
        
    
    return(-1);

【讨论】:

纪元时间不考虑闰秒,所以说“可以以最大的精度和可靠性推导出有关日期的任何其他内容。” 在需要精度的地方具有误导性.干得好,非常感谢! 好吧,我的评论当然是相对于正在进行的事情,即获得一个可靠的日期。您可以可靠地从一个纪元中获取日期,无论纪元是否不够精确。因此,我的意思是(可能是我的错)你可以可靠地从一个时代中得到一个日期,而不是时代本身是可靠的,这是一个不同的故事。

以上是关于在编译时获取纪元时间的主要内容,如果未能解决你的问题,请参考以下文章

将纪元转换为时间戳时获取不正确的日期

Perl:从考虑夏令时的纪元开始以秒为单位输入时间时,获取 gmtime 和本地时间之间的偏移量

如何在编译时获取数组大小?

在编译时从符号表中获取函数名

在编译时从变体中获取类型

如何在 Redshift 中获取纪元时间?