Подтвердить что ты не робот

Как использовать предопределенные макросы __DATE__ и __TIME__ в виде двух целых чисел, а затем строчить?

Хотите использовать __ 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-integer-in-c Можно сослаться на расширение-и-строку-как-получить-марко-имя-не-его-значение

4b9b3361

Ответ 1

Если вы можете использовать компилятор С++ для создания объектного файла, который вы хотите содержать строку версии, то мы можем сделать именно то, что вы хотите! Единственное волшебство здесь в том, что С++ позволяет использовать выражения для статической инициализации массива, а 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
}

Это не тот формат, который вы просили, но я до сих пор не совсем понимаю, как вы хотите, чтобы дни и часы отображались в целое число. Я думаю, что довольно ясно, как сделать это, чтобы создать любую желаемую строку.

Ответ 2

Вот рабочая версия "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 script, который просто создает для вас новый файл include. Вы можете предварительно вычислить все, что захотите, в любом формате. Если вы не хотите Python, мы можем написать AWK script или даже программу C.

Ответ 3

У меня есть частичный ответ для вас. Это основано на том, что я получаю от GCC:

__DATE__ дает что-то вроде "Jul 27 2012"

__TIME__ дает что-то вроде 21:06:19

Поместите этот текст в файл include с именем 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

Я тестировал выше с GCC на Linux. Все работает отлично, за исключением проблемы, что я не могу понять, как получить номер за месяц. Если вы проверите раздел под #if 0, вы увидите мою попытку выяснить месяц. GCC жалуется на это сообщение:

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

Было бы тривиально преобразовать трехбуквенную аббревиатуру месяца в какой-то уникальный номер; просто вычтите "А" из первой буквы и "а" со второго и третьего, а затем переведите в номер базы-26 или что-то еще. Но я хочу, чтобы он оценивал значение 1 для января и т.д., И я не могу понять, как это сделать.

EDIT: Я просто понял, что вы попросили строки, а не выражения, которые оценивают целочисленные значения.

Я попытался использовать эти трюки для создания статической строки:

#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 жалуется, что "элемент инициализации не является константой" для __DATE__.

Извините, я не знаю, как вам помочь. Может быть, вы можете попробовать этот материал с вашим компилятором? Или, может быть, это даст вам представление.

Удачи.

P.S. Если вам не нужны вещи, чтобы быть цифрами, и вам просто нужна уникальная строка сборки, это легко:

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

С GCC это приводит к чему-то вроде:

Version: 1.4 Jul 27 2012 21:53:59

Ответ 4

Вы всегда можете написать простую программу на Python или создать файл include, в котором есть простые операторы #define с номером сборки, временем и датой. Затем вам нужно будет запустить эту программу перед выполнением сборки.

Если вам нравится, я напишу один и отправлю исходный код здесь.

Если вам повезет, ваш инструмент сборки (IDE или что-то еще) может иметь возможность запускать внешнюю команду, а затем вы можете заставить внешний инструмент автоматически переписывать включенный файл с каждой сборкой.

EDIT: здесь программа Python. Это записывает файл с именем build_num.h и имеет номер целочисленной сборки, который начинается с 1 и увеличивается каждый раз при запуске этой программы; он также записывает значения #define для года, месяца, даты, часов, минут и секунд времени выполнения этой программы. Он также имеет #define для основных и второстепенных частей номера версии, плюс полные VERSION и COMPLETE_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() для синтаксического анализа строки.

Ответ 5

Короткий ответ (запрошенная версия): (формат 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 для номера версии:

Makefile:

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, если вы установите майор и дадите десятичным знакам дату + время, например: major.datetime = 1.150710150411

Позволяет заняться бизнесом. Пример ниже будет работать, если вы скомпилируете, как обычно, забудьте установить его или используйте -DVERSION для установки версии непосредственно из оболочки, но лучше всего, я рекомендую третий вариант: используйте 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<=9999 и MINOR<=9999. Конечно, я установил эту высокую ценность, которая, надеюсь, никогда не переполнится. Но использование double еще лучше (плюс, оно полностью автоматическое, не нужно устанавливать MAJOR и MINOR вручную).

Теперь программа выше слишком много. Лучше всего полностью удалить эту функцию и гарантировать, что макрос 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 [email protected]

Лучшая версия с 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 [email protected]

(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;
}

Примечание. Эта двойная функция существует только в том случае, если вы забудете определить макрос ВЕРСИЯ. Если вы используете makefile или установите alias gcc gcc -DVERSION=$(date +"%g%m%d.%H%M%S"), вы можете полностью удалить эту функцию.


Хорошо, что это. Очень аккуратный и простой способ настроить ваш контроль версий и не беспокоиться об этом снова!

Ответ 6

это очень просто....

[in make file]

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

OBJS =....\

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

==== 2 =================== <

DATE = $(дата оболочки + 'char szVersionStr [20] = "% Y-% m-% d% H:% M:% S";') < == lt

all: version $(ProgramID) < == version add сначала

: < < == add

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

[в программе]

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

extern char szVersionStr [20];

[используя]

=== 4 ====

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

Ответ 7

Для тех, кто просто хочет заменить лишний '' (пробел), если день меньше 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] }

Выход: 06 сентября 2019 г.