我正在尝试实现一些琐碎的事情:我需要存储构建时间的32位整数unix时间戳,但是我发现的所有宏(__DATE____TIME____TIMESTAMP__)都扩展为字符串,而不是整数。

似乎,我们还没有(这对我来说很奇怪)。我真的很想拥有整数,而不是字符串。

获得它的最佳实践是什么?

UPD:

附带说明:我做嵌入式工作,因此我没有足够的资源(例如128 KB的闪存),因此解析字符串确实不是一个好主意。

我为什么需要它:我只需要每个beta版本的唯一版本号即可。首先,十六进制文件的名称将类似于my-firmware-v2-33-BETA-1397315745.hex,其次,当我需要在设备屏幕上显示当前版本时,我可能想以各种格式回显它。

最佳答案

因此,我今晚玩得很开心,并创建了一个带有宏的头文件来生成UNIX时间戳,而没有任何外部程序或特殊的编译器功能! 只需包含标题并使用__TIME_UNIX__宏即可。

实际上,代码非常简单:

  • 字符串中的数字字符将按照loreb建议的str[i]-'0'转换为数字,并根据其位置进行称重。
  • 月字符串类似于chux回答被处理;分别检查这些字符,并使用? :运算符将其作为一组进行评估。
  • 用可交换的? :表达式对最后几个月的日子进行计数。
  • ap年的计算很简单,因为在UNIX时间范围内每4年插入一个leap日
  • 最后,将所有单独的值与相应的秒数权衡,以获取UNIX时间。请注意,SEC_PER_DAY必须被减除一次,因为JAN 01 1970, 00:00:00必须是0

  • 该代码已在ATMEL Studio 7(Visual Studio 2015)中使用默认编译器和设置(avr-gcc,-O1优化)进行了测试,并且通过检查生成的.lss文件来确认结果。

    将下面的代码复制并粘贴到头文件中,并在需要时将其包括在内。享受!
    /*
     * compile_time.h
     *
     * Created: 30.05.2017 20:57:58
     *  Author: Dennis (instructable.com/member/nqtronix)
     *
     * This code provides the macro __TIME_UNIX__ which returns the current time in UNIX format. It can
     * be used to identify a version of code on an embedded device, to initialize its RTC and much more.
     * Along that several more constants for seconds, minutes, etc. are provided
     *
     * The macro is based on __TIME__ and __DATE__, which are assumed to be formatted "HH:MM:SS" and
     * "MMM DD YYYY", respectively. The actual value can be calculated by the C compiler at compile time
     * as all inputs are literals. MAKE SURE TO ENABLE OPTIMISATION!
     */
    
    
    #ifndef COMPILE_TIME_H_
    #define COMPILE_TIME_H_
    
    // extracts 1..4 characters from a string and interprets it as a decimal value
    #define CONV_STR2DEC_1(str, i)  (str[i]>'0'?str[i]-'0':0)
    #define CONV_STR2DEC_2(str, i)  (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0')
    #define CONV_STR2DEC_3(str, i)  (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0')
    #define CONV_STR2DEC_4(str, i)  (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0')
    
    // Some definitions for calculation
    #define SEC_PER_MIN             60UL
    #define SEC_PER_HOUR            3600UL
    #define SEC_PER_DAY             86400UL
    #define SEC_PER_YEAR            (SEC_PER_DAY*365)
    #define UNIX_START_YEAR         1970UL
    
    // Custom "glue logic" to convert the month name to a usable number
    #define GET_MONTH(str, i)      (str[i]=='J' && str[i+1]=='a' && str[i+2]=='n' ? 1 :     \
                                    str[i]=='F' && str[i+1]=='e' && str[i+2]=='b' ? 2 :     \
                                    str[i]=='M' && str[i+1]=='a' && str[i+2]=='r' ? 3 :     \
                                    str[i]=='A' && str[i+1]=='p' && str[i+2]=='r' ? 4 :     \
                                    str[i]=='M' && str[i+1]=='a' && str[i+2]=='y' ? 5 :     \
                                    str[i]=='J' && str[i+1]=='u' && str[i+2]=='n' ? 6 :     \
                                    str[i]=='J' && str[i+1]=='u' && str[i+2]=='l' ? 7 :     \
                                    str[i]=='A' && str[i+1]=='u' && str[i+2]=='g' ? 8 :     \
                                    str[i]=='S' && str[i+1]=='e' && str[i+2]=='p' ? 9 :     \
                                    str[i]=='O' && str[i+1]=='c' && str[i+2]=='t' ? 10 :    \
                                    str[i]=='N' && str[i+1]=='o' && str[i+2]=='v' ? 11 :    \
                                    str[i]=='D' && str[i+1]=='e' && str[i+2]=='c' ? 12 : 0)
    
    #define GET_MONTH2DAYS(month)  ((month == 1 ? 0 : 31 +                      \
                                    (month == 2 ? 0 : 28 +                      \
                                    (month == 3 ? 0 : 31 +                      \
                                    (month == 4 ? 0 : 30 +                      \
                                    (month == 5 ? 0 : 31 +                      \
                                    (month == 6 ? 0 : 30 +                      \
                                    (month == 7 ? 0 : 31 +                      \
                                    (month == 8 ? 0 : 31 +                      \
                                    (month == 9 ? 0 : 30 +                      \
                                    (month == 10 ? 0 : 31 +                     \
                                    (month == 11 ? 0 : 30))))))))))))           \
    
    
    #define GET_LEAP_DAYS           ((__TIME_YEARS__-1968)/4 - (__TIME_MONTH__ <=2 ? 1 : 0))
    
    
    
    #define __TIME_SECONDS__        CONV_STR2DEC_2(__TIME__, 6)
    #define __TIME_MINUTES__        CONV_STR2DEC_2(__TIME__, 3)
    #define __TIME_HOURS__          CONV_STR2DEC_2(__TIME__, 0)
    #define __TIME_DAYS__           CONV_STR2DEC_2(__DATE__, 4)
    #define __TIME_MONTH__          GET_MONTH(__DATE__, 0)
    #define __TIME_YEARS__          CONV_STR2DEC_4(__DATE__, 7)
    
    #define __TIME_UNIX__         ((__TIME_YEARS__-UNIX_START_YEAR)*SEC_PER_YEAR+       \
                                    GET_LEAP_DAYS*SEC_PER_DAY+                          \
                                    GET_MONTH2DAYS(__TIME_MONTH__)*SEC_PER_DAY+         \
                                    __TIME_DAYS__*SEC_PER_DAY-SEC_PER_DAY+              \
                                    __TIME_HOURS__*SEC_PER_HOUR+                        \
                                    __TIME_MINUTES__*SEC_PER_MIN+                       \
                                    __TIME_SECONDS__)
    
    #endif /* COMPILE_TIME_H_ */
    

    编辑:

    初始版本不考虑2月份的天数对100和400模年的影响。在2001年和2101年之间这应该不是问题,但是这是一个更通用的宏:
    /*
     *
     * Created: 29.03.2018
     *
     * Authors:
     *
     * Assembled from the code released on Stackoverflow by:
     *   Dennis (instructable.com/member/nqtronix)    |   https://stackoverflow.com/questions/23032002/c-c-how-to-get-integer-unix-timestamp-of-build-time-not-string
     * and
     *   Alexis Wilke                                 |   https://stackoverflow.com/questions/10538444/do-you-know-of-a-c-macro-to-compute-unix-time-and-date
     *
     * Assembled by Jean Rabault
     *
     * UNIX_TIMESTAMP gives the UNIX timestamp (unsigned long integer of seconds since 1st Jan 1970) of compilation from macros using the compiler defined __TIME__ macro.
     * This should include Gregorian calendar leap days, in particular the 29ths of February, 100 and 400 years modulo leaps.
     *
     * Careful: __TIME__ is the local time of the computer, NOT the UTC time in general!
     *
     */
    
    #ifndef COMPILE_TIME_H_
    #define COMPILE_TIME_H_
    
    // Some definitions for calculation
    #define SEC_PER_MIN             60UL
    #define SEC_PER_HOUR            3600UL
    #define SEC_PER_DAY             86400UL
    #define SEC_PER_YEAR            (SEC_PER_DAY*365)
    
    // extracts 1..4 characters from a string and interprets it as a decimal value
    #define CONV_STR2DEC_1(str, i)  (str[i]>'0'?str[i]-'0':0)
    #define CONV_STR2DEC_2(str, i)  (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0')
    #define CONV_STR2DEC_3(str, i)  (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0')
    #define CONV_STR2DEC_4(str, i)  (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0')
    
    // Custom "glue logic" to convert the month name to a usable number
    #define GET_MONTH(str, i)      (str[i]=='J' && str[i+1]=='a' && str[i+2]=='n' ? 1 :     \
                                    str[i]=='F' && str[i+1]=='e' && str[i+2]=='b' ? 2 :     \
                                    str[i]=='M' && str[i+1]=='a' && str[i+2]=='r' ? 3 :     \
                                    str[i]=='A' && str[i+1]=='p' && str[i+2]=='r' ? 4 :     \
                                    str[i]=='M' && str[i+1]=='a' && str[i+2]=='y' ? 5 :     \
                                    str[i]=='J' && str[i+1]=='u' && str[i+2]=='n' ? 6 :     \
                                    str[i]=='J' && str[i+1]=='u' && str[i+2]=='l' ? 7 :     \
                                    str[i]=='A' && str[i+1]=='u' && str[i+2]=='g' ? 8 :     \
                                    str[i]=='S' && str[i+1]=='e' && str[i+2]=='p' ? 9 :     \
                                    str[i]=='O' && str[i+1]=='c' && str[i+2]=='t' ? 10 :    \
                                    str[i]=='N' && str[i+1]=='o' && str[i+2]=='v' ? 11 :    \
                                    str[i]=='D' && str[i+1]=='e' && str[i+2]=='c' ? 12 : 0)
    
    // extract the information from the time string given by __TIME__ and __DATE__
    #define __TIME_SECONDS__        CONV_STR2DEC_2(__TIME__, 6)
    #define __TIME_MINUTES__        CONV_STR2DEC_2(__TIME__, 3)
    #define __TIME_HOURS__          CONV_STR2DEC_2(__TIME__, 0)
    #define __TIME_DAYS__           CONV_STR2DEC_2(__DATE__, 4)
    #define __TIME_MONTH__          GET_MONTH(__DATE__, 0)
    #define __TIME_YEARS__          CONV_STR2DEC_4(__DATE__, 7)
    
    // Days in February
    #define _UNIX_TIMESTAMP_FDAY(year) \
        (((year) % 400) == 0UL ? 29UL : \
            (((year) % 100) == 0UL ? 28UL : \
                (((year) % 4) == 0UL ? 29UL : \
                    28UL)))
    
    // Days in the year
    #define _UNIX_TIMESTAMP_YDAY(year, month, day) \
        ( \
            /* January */    day \
            /* February */ + (month >=  2 ? 31UL : 0UL) \
            /* March */    + (month >=  3 ? _UNIX_TIMESTAMP_FDAY(year) : 0UL) \
            /* April */    + (month >=  4 ? 31UL : 0UL) \
            /* May */      + (month >=  5 ? 30UL : 0UL) \
            /* June */     + (month >=  6 ? 31UL : 0UL) \
            /* July */     + (month >=  7 ? 30UL : 0UL) \
            /* August */   + (month >=  8 ? 31UL : 0UL) \
            /* September */+ (month >=  9 ? 31UL : 0UL) \
            /* October */  + (month >= 10 ? 30UL : 0UL) \
            /* November */ + (month >= 11 ? 31UL : 0UL) \
            /* December */ + (month >= 12 ? 30UL : 0UL) \
        )
    
    // get the UNIX timestamp from a digits representation
    #define _UNIX_TIMESTAMP(year, month, day, hour, minute, second) \
        ( /* time */ second \
                    + minute * SEC_PER_MIN \
                    + hour * SEC_PER_HOUR \
        + /* year day (month + day) */ (_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * SEC_PER_DAY \
        + /* year */ (year - 1970UL) * SEC_PER_YEAR \
                    + ((year - 1969UL) / 4UL) * SEC_PER_DAY \
                    - ((year - 1901UL) / 100UL) * SEC_PER_DAY \
                    + ((year - 1601UL) / 400UL) * SEC_PER_DAY \
        )
    
    // the UNIX timestamp
    #define UNIX_TIMESTAMP (_UNIX_TIMESTAMP(__TIME_YEARS__, __TIME_MONTH__, __TIME_DAYS__, __TIME_HOURS__, __TIME_MINUTES__, __TIME_SECONDS__))
    
    #endif
    

    关于c++ - C/C++ : how to get integer unix timestamp of build time (not string),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23032002/

    10-13 08:03