如何使用__DATE__和__TIME__预定义的宏作为两个整数,然后stringify?

时间:2012-07-28 02:40:48

标签: c macros predefined-macro

想要使用 __ DATE __和__ TIME __ 作为整数,以便在编译时为我的代码提供自动版本。

#define STRINGIZER(arg)     #arg
#define STR_VALUE(arg)      STRINGIZER(arg)

#define DATE_as_int_str useD(__DATE__) // What can be done ?
#define TIME_as_int_str useT(__TIME__) // What can be done ?

#define VERSION 1.4

#define COMPLETE_VERSION STR_VALUE(VERSION) "." DATE_as_int_str "." TIME_as_int_str

并将COMPLETE_VERSION作为const unsigned char []中的字符串。

const unsigned char completeVersion[] = ?? COMPLETE_VERSION;

应该输出 1.4.1432.2234

可能的解决方案之一可能但不起作用: convert-date-to-unsigned-int

在编译时间 convertint-date-and-time-string-to-just-integers-in-c 的上下文中 可以参考 expanssion-and-stringification-how-to-get-the-marco-name-not-its-value

7 个答案:

答案 0 :(得分:42)

如果您可以使用C ++编译器来构建要包含版本字符串的目标文件,那么我们可以完全按照您的要求进行操作!这里唯一的魔力是C ++允许你使用表达式静态初始化一个数组,而C则不然。表达式需要在编译时完全可计算,但这些表达式都是,所以没问题。

我们一次一个字节地构建版本字符串,并获得我们想要的内容。

// source file version_num.h

#ifndef VERSION_NUM_H

#define VERSION_NUM_H


#define VERSION_MAJOR 1
#define VERSION_MINOR 4


#endif // VERSION_NUM_H

// source file build_defs.h

#ifndef BUILD_DEFS_H

#define BUILD_DEFS_H


// Example of __DATE__ string: "Jul 27 2012"
//                              01234567890

#define BUILD_YEAR_CH0 (__DATE__[ 7])
#define BUILD_YEAR_CH1 (__DATE__[ 8])
#define BUILD_YEAR_CH2 (__DATE__[ 9])
#define BUILD_YEAR_CH3 (__DATE__[10])


#define BUILD_MONTH_IS_JAN (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n')
#define BUILD_MONTH_IS_FEB (__DATE__[0] == 'F')
#define BUILD_MONTH_IS_MAR (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r')
#define BUILD_MONTH_IS_APR (__DATE__[0] == 'A' && __DATE__[1] == 'p')
#define BUILD_MONTH_IS_MAY (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y')
#define BUILD_MONTH_IS_JUN (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n')
#define BUILD_MONTH_IS_JUL (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l')
#define BUILD_MONTH_IS_AUG (__DATE__[0] == 'A' && __DATE__[1] == 'u')
#define BUILD_MONTH_IS_SEP (__DATE__[0] == 'S')
#define BUILD_MONTH_IS_OCT (__DATE__[0] == 'O')
#define BUILD_MONTH_IS_NOV (__DATE__[0] == 'N')
#define BUILD_MONTH_IS_DEC (__DATE__[0] == 'D')


#define BUILD_MONTH_CH0 \
    ((BUILD_MONTH_IS_OCT || BUILD_MONTH_IS_NOV || BUILD_MONTH_IS_DEC) ? '1' : '0')

#define BUILD_MONTH_CH1 \
    ( \
        (BUILD_MONTH_IS_JAN) ? '1' : \
        (BUILD_MONTH_IS_FEB) ? '2' : \
        (BUILD_MONTH_IS_MAR) ? '3' : \
        (BUILD_MONTH_IS_APR) ? '4' : \
        (BUILD_MONTH_IS_MAY) ? '5' : \
        (BUILD_MONTH_IS_JUN) ? '6' : \
        (BUILD_MONTH_IS_JUL) ? '7' : \
        (BUILD_MONTH_IS_AUG) ? '8' : \
        (BUILD_MONTH_IS_SEP) ? '9' : \
        (BUILD_MONTH_IS_OCT) ? '0' : \
        (BUILD_MONTH_IS_NOV) ? '1' : \
        (BUILD_MONTH_IS_DEC) ? '2' : \
        /* error default */    '?' \
    )

#define BUILD_DAY_CH0 ((__DATE__[4] >= '0') ? (__DATE__[4]) : '0')
#define BUILD_DAY_CH1 (__DATE__[ 5])



// Example of __TIME__ string: "21:06:19"
//                              01234567

#define BUILD_HOUR_CH0 (__TIME__[0])
#define BUILD_HOUR_CH1 (__TIME__[1])

#define BUILD_MIN_CH0 (__TIME__[3])
#define BUILD_MIN_CH1 (__TIME__[4])

#define BUILD_SEC_CH0 (__TIME__[6])
#define BUILD_SEC_CH1 (__TIME__[7])


#if VERSION_MAJOR > 100

#define VERSION_MAJOR_INIT \
    ((VERSION_MAJOR / 100) + '0'), \
    (((VERSION_MAJOR % 100) / 10) + '0'), \
    ((VERSION_MAJOR % 10) + '0')

#elif VERSION_MAJOR > 10

#define VERSION_MAJOR_INIT \
    ((VERSION_MAJOR / 10) + '0'), \
    ((VERSION_MAJOR % 10) + '0')

#else

#define VERSION_MAJOR_INIT \
    (VERSION_MAJOR + '0')

#endif

#if VERSION_MINOR > 100

#define VERSION_MINOR_INIT \
    ((VERSION_MINOR / 100) + '0'), \
    (((VERSION_MINOR % 100) / 10) + '0'), \
    ((VERSION_MINOR % 10) + '0')

#elif VERSION_MINOR > 10

#define VERSION_MINOR_INIT \
    ((VERSION_MINOR / 10) + '0'), \
    ((VERSION_MINOR % 10) + '0')

#else

#define VERSION_MINOR_INIT \
    (VERSION_MINOR + '0')

#endif



#endif // BUILD_DEFS_H

// source file main.c

#include "version_num.h"
#include "build_defs.h"

// want something like: 1.4.1432.2234

const unsigned char completeVersion[] =
{
    VERSION_MAJOR_INIT,
    '.',
    VERSION_MINOR_INIT,
    '-', 'V', '-',
    BUILD_YEAR_CH0, BUILD_YEAR_CH1, BUILD_YEAR_CH2, BUILD_YEAR_CH3,
    '-',
    BUILD_MONTH_CH0, BUILD_MONTH_CH1,
    '-',
    BUILD_DAY_CH0, BUILD_DAY_CH1,
    'T',
    BUILD_HOUR_CH0, BUILD_HOUR_CH1,
    ':',
    BUILD_MIN_CH0, BUILD_MIN_CH1,
    ':',
    BUILD_SEC_CH0, BUILD_SEC_CH1,
    '\0'
};


#include <stdio.h>

int main(int argc, char **argv)
{
    printf("%s\n", completeVersion);
    // prints something similar to: 1.4-V-2013-05-09T15:34:49
}

这不是您要求的格式,但我仍然不完全了解您希望日期和小时映射到整数的方式。我认为如何使这产生任何所需的字符串非常清楚。

答案 1 :(得分:14)

这是“build defs”的工作版本。这与我之前的回答相似,但我想出了构建月份。 (您无法在#if语句中计算构建月份,但可以使用将编译为常量的三元表达式。)

另外,根据文档,如果编译器无法获取时间,它将为您提供这些字符串的问号。所以我为这种情况添加了测试,如果发生这种情况,会使各种宏返回一个明显错误的值(99)。

#ifndef BUILD_DEFS_H

#define BUILD_DEFS_H


// Example of __DATE__ string: "Jul 27 2012"
// Example of __TIME__ string: "21:06:19"

#define COMPUTE_BUILD_YEAR \
    ( \
        (__DATE__[ 7] - '0') * 1000 + \
        (__DATE__[ 8] - '0') *  100 + \
        (__DATE__[ 9] - '0') *   10 + \
        (__DATE__[10] - '0') \
    )


#define COMPUTE_BUILD_DAY \
    ( \
        ((__DATE__[4] >= '0') ? (__DATE__[4] - '0') * 10 : 0) + \
        (__DATE__[5] - '0') \
    )


#define BUILD_MONTH_IS_JAN (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n')
#define BUILD_MONTH_IS_FEB (__DATE__[0] == 'F')
#define BUILD_MONTH_IS_MAR (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r')
#define BUILD_MONTH_IS_APR (__DATE__[0] == 'A' && __DATE__[1] == 'p')
#define BUILD_MONTH_IS_MAY (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y')
#define BUILD_MONTH_IS_JUN (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n')
#define BUILD_MONTH_IS_JUL (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l')
#define BUILD_MONTH_IS_AUG (__DATE__[0] == 'A' && __DATE__[1] == 'u')
#define BUILD_MONTH_IS_SEP (__DATE__[0] == 'S')
#define BUILD_MONTH_IS_OCT (__DATE__[0] == 'O')
#define BUILD_MONTH_IS_NOV (__DATE__[0] == 'N')
#define BUILD_MONTH_IS_DEC (__DATE__[0] == 'D')


#define COMPUTE_BUILD_MONTH \
    ( \
        (BUILD_MONTH_IS_JAN) ?  1 : \
        (BUILD_MONTH_IS_FEB) ?  2 : \
        (BUILD_MONTH_IS_MAR) ?  3 : \
        (BUILD_MONTH_IS_APR) ?  4 : \
        (BUILD_MONTH_IS_MAY) ?  5 : \
        (BUILD_MONTH_IS_JUN) ?  6 : \
        (BUILD_MONTH_IS_JUL) ?  7 : \
        (BUILD_MONTH_IS_AUG) ?  8 : \
        (BUILD_MONTH_IS_SEP) ?  9 : \
        (BUILD_MONTH_IS_OCT) ? 10 : \
        (BUILD_MONTH_IS_NOV) ? 11 : \
        (BUILD_MONTH_IS_DEC) ? 12 : \
        /* error default */  99 \
    )

#define COMPUTE_BUILD_HOUR ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0')
#define COMPUTE_BUILD_MIN  ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0')
#define COMPUTE_BUILD_SEC  ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0')


#define BUILD_DATE_IS_BAD (__DATE__[0] == '?')

#define BUILD_YEAR  ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_YEAR)
#define BUILD_MONTH ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_MONTH)
#define BUILD_DAY   ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_DAY)

#define BUILD_TIME_IS_BAD (__TIME__[0] == '?')

#define BUILD_HOUR  ((BUILD_TIME_IS_BAD) ? 99 :  COMPUTE_BUILD_HOUR)
#define BUILD_MIN   ((BUILD_TIME_IS_BAD) ? 99 :  COMPUTE_BUILD_MIN)
#define BUILD_SEC   ((BUILD_TIME_IS_BAD) ? 99 :  COMPUTE_BUILD_SEC)


#endif // BUILD_DEFS_H

使用以下测试代码,上述工作非常有用:

printf("%04d-%02d-%02dT%02d:%02d:%02d\n", BUILD_YEAR, BUILD_MONTH, BUILD_DAY, BUILD_HOUR, BUILD_MIN, BUILD_SEC);

但是,当我尝试将这些宏与您的字符串化宏一起使用时,它会对文字表达式进行字符串化!我不知道有什么办法让编译器将表达式缩减为文字整数值然后进行字符串化。

此外,如果您尝试使用这些宏静态初始化值数组,编译器会发出error: initializer element is not constant消息。所以你不能用这些宏做你想做的事。

此时我认为最好的选择是Python脚本,它只为您生成一个新的包含文件。您可以以任何所需的格式预先计算任何所需的内容。如果您不想要Python,我们可以编写AWK脚本甚至是C程序。

答案 2 :(得分:9)

我有一个部分答案。这是基于我从GCC得到的:

__DATE__提供类似"Jul 27 2012"

的内容

__TIME__提供类似21:06:19

的内容

将此文本放在名为build_defs.h的包含文件中:

#ifndef BUILD_DEFS_H

#define BUILD_DEFS_H


#define BUILD_YEAR ((__DATE__[7] - '0') * 1000 +  (__DATE__[8] - '0') * 100 + (__DATE__[9] - '0') * 10 + __DATE__[10] - '0')

#define BUILD_DATE ((__DATE__[4] - '0') * 10 + __DATE__[5] - '0')


#if 0
#if (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n')
    #define BUILD_MONTH  1
#elif (__DATE__[0] == 'F' && __DATE__[1] == 'e' && __DATE__[2] == 'b')
    #define BUILD_MONTH  2
#elif (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r')
    #define BUILD_MONTH  3
#elif (__DATE__[0] == 'A' && __DATE__[1] == 'p' && __DATE__[2] == 'r')
    #define BUILD_MONTH  4
#elif (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y')
    #define BUILD_MONTH  5
#elif (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n')
    #define BUILD_MONTH  6
#elif (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l')
    #define BUILD_MONTH  7
#elif (__DATE__[0] == 'A' && __DATE__[1] == 'u' && __DATE__[2] == 'g')
    #define BUILD_MONTH  8
#elif (__DATE__[0] == 'S' && __DATE__[1] == 'e' && __DATE__[2] == 'p')
    #define BUILD_MONTH  9
#elif (__DATE__[0] == 'O' && __DATE__[1] == 'c' && __DATE__[2] == 't')
    #define BUILD_MONTH 10
#elif (__DATE__[0] == 'N' && __DATE__[1] == 'o' && __DATE__[2] == 'v')
    #define BUILD_MONTH 11
#elif (__DATE__[0] == 'D' && __DATE__[1] == 'e' && __DATE__[2] == 'c')
    #define BUILD_MONTH 12
#else
    #error "Could not figure out month"
#endif
#endif

#define BUILD_HOUR ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0')
#define BUILD_MIN ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0')
#define BUILD_SEC ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0')

#endif // BUILD_DEFS_H

我在Linux上使用GCC测试了上述内容。这一切都很有效,除了我无法弄清楚如何得到这个月的数字的问题。如果您查看#if 0下的部分,您会看到我尝试计算月份。 GCC抱怨这条消息:

error: token ""Jul 27 2012"" is not valid in preprocessor expressions

将三个字母的月份缩写转换为某种独特的数字是微不足道的;只需减去A&#39;从第一个字母和&#39; a&#39;从第二个和第三个,然后转换为基数为26的数字或其他东西。但是我想让它在1月份评估为1,依此类推,我无法弄清楚如何做到这一点。

编辑:我刚刚意识到你要求字符串,而不是求值为整数值的表达式。

我尝试使用这些技巧来构建静态字符串:

#define BUILD_MAJOR 1
#define BUILD_MINOR 4
#define VERSION STRINGIZE(BUILD_MAJOR) "." STRINGIZE(BUILD_MINOR)

char build_str[] = {
    BUILD_MAJOR + '0', '.' BUILD_MINOR + '0', '.',
    __DATE__[7], __DATE__[8], __DATE__[9], __DATE__[10],
    '\0'
};

GCC抱怨&#34;初始化元素不是常数&#34; __DATE__

抱歉,我不确定如何帮助你。也许你可以用编译器尝试这些东西?或许它会给你一个想法。

祝你好运。

P.S。如果你不需要数字,你只需要一个独特的构建字符串,那就很简单了:

const char *build_str = "Version: " VERSION " " __DATE__ " " __TIME__;

使用GCC,结果如下:

Version: 1.4 Jul 27 2012 21:53:59

答案 3 :(得分:8)

你总是可以用Python编写一个简单的程序来创建一个包含文件,该文件包含带有内部版本号,时间和日期的简单#define语句。然后,您需要在构建之前运行此程序。

如果你愿意,我会在这里写一个并发布消息来源。

如果幸运的话,您的构建工具(IDE或其他)可能能够运行外部命令,然后您可以让外部工具在每次构建时自动重写包含文件。

编辑:这是一个Python程序。这会写一个名为build_num.h的文件,其整数内部版本号从1开始,每次运行该程序时都会递增;它还会为该程序运行的年份,月份,日期,小时,分钟和秒写入#define值。它还包含#define版本号的主要部分和次要部分,以及您想要的完整VERSIONCOMPLETE_VERSION。 (我不确定你想要的日期和时间数字,所以我只是从日期和时间开始连接数字。你可以很容易地改变它。)

每次运行它时,它都会读入build_num.h文件,并对其进行解析以获取内部版本号;如果build_num.h文件不存在,则会在1处开始构建编号。同样,它会解析主要版本号和次要版本号,如果该文件不存在,则默认为版本0.1。

import time

FNAME = "build_num.h"

build_num = None
version_major = None
version_minor = None

DEF_BUILD_NUM = "#define BUILD_NUM "
DEF_VERSION_MAJOR = "#define VERSION_MAJOR "
DEF_VERSION_MINOR = "#define VERSION_MINOR "

def get_int(s_marker, line):
    _, _, s = line.partition(s_marker) # we want the part after the marker
    return int(s)

try:
    with open(FNAME) as f:
        for line in f:
            if DEF_BUILD_NUM in line:
                build_num = get_int(DEF_BUILD_NUM, line)
                build_num += 1
            elif DEF_VERSION_MAJOR in line:
                version_major = get_int(DEF_VERSION_MAJOR, line)
            elif DEF_VERSION_MINOR in line:
                version_minor = get_int(DEF_VERSION_MINOR, line)
except IOError:
    build_num = 1
    version_major = 0
    version_minor = 1

assert None not in (build_num, version_major, version_minor)


with open(FNAME, 'w') as f:
    f.write("#ifndef BUILD_NUM_H\n")
    f.write("#define BUILD_NUM_H\n")
    f.write("\n")
    f.write(DEF_BUILD_NUM + "%d\n" % build_num)
    f.write("\n")
    t = time.localtime()
    f.write("#define BUILD_YEAR %d\n" % t.tm_year)
    f.write("#define BUILD_MONTH %d\n" % t.tm_mon)
    f.write("#define BUILD_DATE %d\n" % t.tm_mday)
    f.write("#define BUILD_HOUR %d\n" % t.tm_hour)
    f.write("#define BUILD_MIN %d\n" % t.tm_min)
    f.write("#define BUILD_SEC %d\n" % t.tm_sec)
    f.write("\n")
    f.write("#define VERSION_MAJOR %d\n" % version_major)
    f.write("#define VERSION_MINOR %d\n" % version_minor)
    f.write("\n")
    f.write("#define VERSION \"%d.%d\"\n" % (version_major, version_minor))
    s = "%d.%d.%04d%02d%02d.%02d%02d%02d" % (version_major, version_minor,
            t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec)
    f.write("#define COMPLETE_VERSION \"%s\"\n" % s)
    f.write("\n")
    f.write("#endif // BUILD_NUM_H\n")

我将所有定义都设为整数,但由于它们是简单的整数,因此如果您愿意,可以使用标准的字符串化技巧来构建字符串。此外,您可以简单地扩展它以构建其他预定义的字符串。

这个程序应该在Python 2.6或更高版本下正常运行,包括任何Python 3.x版本。您可以在旧的Python下运行它并进行一些更改,例如不使用.partition()来解析字符串。

答案 4 :(得分:4)

简答(问题版):(格式3.33.20150710.182906)

请简单地使用makefile

MAJOR = 3
MINOR = 33
BUILD = $(shell date +"%Y%m%d.%H%M%S")
VERSION = "\"$(MAJOR).$(MINOR).$(BUILD)\""
CPPFLAGS = -DVERSION=$(VERSION)

program.x : source.c
       gcc $(CPPFLAGS) source.c -o program.x

如果你不想要makefile,那么更短,只需编译:

gcc source.c -o program.x -DVERSION=\"2.22.$(date +"%Y%m%d.%H%M%S")\"

简答题(建议版本):(格式150710.182906)

使用double版本号:

生成文件:

VERSION = $(shell date +"%g%m%d.%H%M%S")
CPPFLAGS = -DVERSION=$(VERSION)
program.x : source.c
      gcc $(CPPFLAGS) source.c -o program.x

或简单的bash命令:

$ gcc source.c -o program.x -DVERSION=$(date +"%g%m%d.%H%M%S")

提示 仍然不喜欢makefile或仅仅是为了一个不那么小的测试程序?添加以下行:

 export CPPFLAGS='-DVERSION='$(date +"%g%m%d.%H%M%S")

到您的~/.profile,并记住使用gcc $CPPFLAGS ...

进行编译

答案很长:

我知道这个问题比较老,但我做的贡献不大。最佳实践总是自动化否则可能成为错误(或遗忘)的来源。

我习惯了为我创建版本号的函数。但我更喜欢这个函数返回float。我的版本号可以通过以下方式打印:printf("%13.6f\n", version());,例如:150710.150411(年份(2位数),DOT小时分钟秒)。

但是,问题是你的问题。如果您更喜欢“major.minor.date.time”,则必须是一个字符串。 (相信我,double会更好。如果你坚持使用专业,你仍然可以使用double,如果你设置专业,让小数为日期+时间,如:major.datetime = 1.150710150411

让我们开展业务。如果您像往常一样编译,忘记设置它,或者使用-DVERSION直接从shell设置版本,示例bellow将会起作用,但更好的是,我建议使用第三个选项:使用makefile

三种形式的编译和结果:

使用make:

beco> make program.x
gcc -Wall -Wextra -g -O0 -ansi -pedantic-errors -c -DVERSION="\"3.33.20150710.045829\"" program.c -o program.o
gcc  program.o -o program.x

运行:

__DATE__: 'Jul 10 2015'
__TIME__: '04:58:29'
VERSION: '3.33.20150710.045829'

使用-DVERSION:

beco> gcc program.c -o program.x -Wall -Wextra -g -O0 -ansi -pedantic-errors -DVERSION=\"2.22.$(date +"%Y%m%d.%H%M%S")\"

运行:

__DATE__: 'Jul 10 2015'
__TIME__: '04:58:37'
VERSION: '2.22.20150710.045837'

使用内置功能:

beco> gcc program.c -o program.x -Wall -Wextra -g -O0 -ansi -pedantic-errors

运行:

__DATE__: 'Jul 10 2015'
__TIME__: '04:58:43'
VERSION(): '1.11.20150710.045843'

源代码

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #define FUNC_VERSION (0)
  6 #ifndef VERSION
  7   #define MAJOR 1
  8   #define MINOR 11
  9   #define VERSION version()
 10   #undef FUNC_VERSION
 11   #define FUNC_VERSION (1)
 12   char sversion[]="9999.9999.20150710.045535";
 13 #endif
 14 
 15 #if(FUNC_VERSION)
 16 char *version(void);
 17 #endif
 18 
 19 int main(void)
 20 {
 21 
 22   printf("__DATE__: '%s'\n", __DATE__);
 23   printf("__TIME__: '%s'\n", __TIME__);
 24 
 25   printf("VERSION%s: '%s'\n", (FUNC_VERSION?"()":""), VERSION);
 26   return 0;
 27 }
 28 
 29 /* String format: */
 30 /* __DATE__="Oct  8 2013" */
 31 /*  __TIME__="00:13:39" */
 32
 33 /* Version Function: returns the version string */
 34 #if(FUNC_VERSION)
 35 char *version(void)
 36 {
 37   const char data[]=__DATE__;
 38   const char tempo[]=__TIME__;
 39   const char nomes[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
 40   char omes[4];
 41   int ano, mes, dia, hora, min, seg;
 42 
 43   if(strcmp(sversion,"9999.9999.20150710.045535"))
 44     return sversion;
 45 
 46   if(strlen(data)!=11||strlen(tempo)!=8)
 47     return NULL;
 48 
 49   sscanf(data, "%s %d %d", omes, &dia, &ano);
 50   sscanf(tempo, "%d:%d:%d", &hora, &min, &seg);
 51   mes=(strstr(nomes, omes)-nomes)/3+1;
 52   sprintf(sversion,"%d.%d.%04d%02d%02d.%02d%02d%02d", MAJOR, MINOR, ano, mes, dia, hora, min, seg);
 53 
 54   return sversion;
 55 }
 56 #endif

请注意,该字符串受MAJOR<=9999MINOR<=9999限制。当然,我设置了这个值很高的值,希望永远不会溢出。但使用double仍然更好(另外,它是完全自动的,无需手动设置MAJORMINOR

现在,上面的程序有点太多了。更好的方法是完全删除该函数,并保证宏VERSION被定义为-DVERSION直接进入GCC命令行(或自动添加它的别名,以免你忘记),或者建议的解决方案,将此流程包含在makefile

这是我使用的makefile

MakeFile来源:

  1   MAJOR = 3
  2   MINOR = 33
  3   BUILD = $(shell date +"%Y%m%d.%H%M%S")
  4   VERSION = "\"$(MAJOR).$(MINOR).$(BUILD)\""
  5   CC = gcc
  6   CFLAGS = -Wall -Wextra -g -O0 -ansi -pedantic-errors
  7   CPPFLAGS = -DVERSION=$(VERSION)
  8   LDLIBS =
  9   
 10    %.x : %.c
 11          $(CC) $(CFLAGS) $(CPPFLAGS) $(LDLIBS) $^ -o $@

使用DOUBLE的更好版本

现在我向您展示了“您的”首选解决方案,这是我的解决方案:

直接与(a)makefile或(b)gcc编译:

(a)MakeFile:

   VERSION = $(shell date +"%g%m%d.%H%M%S")
   CC = gcc
   CFLAGS = -Wall -Wextra -g -O0 -ansi -pedantic-errors 
   CPPFLAGS = -DVERSION=$(VERSION)
   LDLIBS =
   %.x : %.c
         $(CC) $(CFLAGS) $(CPPFLAGS) $(LDLIBS) $^ -o $@

(b)或简单的bash命令:

 $ gcc program.c -o program.x -Wall -Wextra -g -O0 -ansi -pedantic-errors -DVERSION=$(date +"%g%m%d.%H%M%S")

源代码(双版):

#ifndef VERSION
  #define VERSION version()
#endif

double version(void);

int main(void)
{
  printf("VERSION%s: '%13.6f'\n", (FUNC_VERSION?"()":""), VERSION);
  return 0;
}

double version(void)
{
  const char data[]=__DATE__;
  const char tempo[]=__TIME__;
  const char nomes[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  char omes[4];
  int ano, mes, dia, hora, min, seg;
  char sversion[]="130910.001339";
  double fv;

  if(strlen(data)!=11||strlen(tempo)!=8)
    return -1.0;

  sscanf(data, "%s %d %d", omes, &dia, &ano);
  sscanf(tempo, "%d:%d:%d", &hora, &min, &seg);
  mes=(strstr(nomes, omes)-nomes)/3+1;
  sprintf(sversion,"%04d%02d%02d.%02d%02d%02d", ano, mes, dia, hora, min, seg);
  fv=atof(sversion);

  return fv;
}

注意:只有在您忘记定义宏VERSION时才会出现此双重功能。如果您使用makefile或设置alias gcc gcc -DVERSION=$(date +"%g%m%d.%H%M%S"),则可以安全地完全删除此功能。

嗯,就是这样。一个非常简洁的方法来设置您的版本控制,再也不用担心它了!

答案 5 :(得分:0)

非常简单......

[在make文件中]

==== 1 ===================

OBJS = .... \

version.o <<== add to your obj lists

==== 2 ===================

DATE = $(shell date +'char szVersionStr [20] =“%Y-%m-%d%H:%M:%S”;')&lt;&lt; == add

all:版本$(ProgramID)&lt;&lt; ==版本添加首先

版本:&lt;&lt; ==添加

echo '$(DATE)' > version.c  <== add ( create version.c file)

[在节目中]

===== 3 =============

extern char szVersionStr [20];

[使用]

=== 4 ====

printf( "Version: %s\n", szVersionStr );

答案 6 :(得分:0)

对于任何希望在天数少于10的情况下替换多余的''(空格)的人,请使用:

#define BUILD_DATE (char const[]) { __DATE__[0], __DATE__[1], __DATE__[2], __DATE__[3], (__DATE__[4] == ' ' ?  '0' : __DATE__[4]), __DATE__[5], __DATE__[6], __DATE__[7], __DATE__[8], __DATE__[9], __DATE__[10], __DATE__[11] }

输出:2019年9月6日