2012-07-28 4 views
29

Chcesz używać __ DATA __ i __ TIME __ jako liczba całkowita dla automatycznego udostępniania mojego kodu w czasie kompilacji.Jak korzystać z __DATA__ i __TIME__ wstępnie zdefiniowanych makr w postaci dwóch liczb całkowitych, a następnie uszeregować?

#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 

i dostać COMPLETE_VERSION jako ciąg w const unsigned char [].

const unsigned char completeVersion[] = ?? COMPLETE_VERSION; 

powinien wypisać 1.4.1432.2234 coś.

Jednym z możliwych rozwiązań może być, ale nie działa: convert-date-to-unsigned-int

W kontekście kompilacji convertint-date-and-time-string-to-just-integers-in-c Można odnieść expanssion-and-stringification-how-to-get-the-marco-name-not-its-value

+1

Twój '_VERSION' makro narusza zasadę identyfikator, który począwszy od znaku podkreślenia, po którym następuje litera jest zarezerwowana dla realizacji . – chris

+0

@chris: Zmieniam identyfikator. Włożę coś jeszcze. inna zmienna "VERSION" już istnieje w moim kodzie, więc zastanawiam się, co można zrobić. – Rick2047

+1

Dopóki nie zaczyna się od dwóch podkreśleń, powinieneś być w porządku. – chris

Odpowiedz

5

mam częściową odpowiedź dla Ciebie. Opiera się to na co mam z GCC:

__DATE__ daje coś takiego "Jul 27 2012"

__TIME__ daje coś 21:06:19

umieścić ten tekst w pliku dołączanego nazywa 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 

I testowałem powyższe z GCC na Linuksie. Wszystko działa świetnie, z wyjątkiem problemu, że nie mogę wymyślić, jak zdobyć numer na miesiąc. Jeśli sprawdzisz sekcję pod numerem #if 0, zobaczysz moją próbę ustalenia miesiąca. GCC narzeka z tej wiadomości:

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

byłoby trywialne do konwersji trzyliterowy skrót nazwy miesiąca w jakimś unikalnym numerem; po prostu odejmij "A" od pierwszej litery i "a" od drugiej i trzeciej, a następnie przekonwertuj na liczbę podstawową-26 lub coś podobnego. Ale chcę, żeby była oceniona na 1 dla stycznia i tak dalej, i nie mogę wymyślić, jak to zrobić.

EDYCJA: Właśnie zdałem sobie sprawę, że prosiłeś o ciągi, a nie wyrażenia, które oceniają wartości całkowite.

Starałem się korzystać z tych sztuczek, aby zbudować ciąg statyczny:

#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 narzeka, że ​​„elementem Inicjator nie jest stała” dla __DATE__.

Niestety, nie jestem pewien, jak ci pomóc. Może możesz wypróbować te rzeczy z kompilatorem? A może to da ci pomysł.

Powodzenia.

P.S.Jeśli nie potrzebujemy rzeczy być liczbami, a chcesz tylko unikalny build ciąg, to proste:

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

z GCC, skutkuje to coś takiego:

Version: 1.4 Jul 27 2012 21:53:59 
+0

Muszę poprawnie napisać #define BUILD_HOUR ((__ TIME __ [0] - '0') * 10 + __TIME__ [1] - "0"). Jeśli używam const unsigned char df [] = BUILD_HOUR. Nie drukuje nic lub drukuje równoważne int. Jeśli zaznaczę, że daje wydruki (("10:24:33" [0] - "0") * 10 + "10:24:33" [1] - "0"). Chodzi o __ TIME __ jest już ciągiem. – Rick2047

+0

Myślę, że będzie musiał przejść z ** Wersja: 1.4 lipca 27 2012 21: 53: 59 **. Ale wciąż szukam odpowiedzi. – Rick2047

+0

Wydaje się, że nikt nie chce podejmować wyzwania poza u. Wziąłem to. : P – Rick2047

6

Zawsze można napisać prosty program w Pythonie lub coś, co tworzy plik włączający, który ma proste instrukcje o numerze kompilacji, czasie i dacie. Będziesz wtedy musiał uruchomić ten program przed wykonaniem kompilacji.

Jeśli chcesz, napiszę i opublikuję tutaj.

Jeśli masz szczęście, narzędzie do budowania (IDE lub cokolwiek innego) może mieć możliwość uruchamiania zewnętrznego polecenia, a następnie możesz mieć narzędzie zewnętrzne automatycznie przepisać plik dołączany automatycznie dla każdej kompilacji.

EDYCJA: Oto program w języku Python. Spowoduje to zapisanie pliku o nazwie build_num.h i ma numer kompilacji całkowitej, który zaczyna się od 1 i zwiększa się za każdym razem, gdy ten program jest uruchamiany; zapisuje również wartości #define dla roku, miesiąca, daty, godzin, minut i sekund czasu uruchomienia tego programu. Ma on także dla głównych i pomniejszych części numeru wersji, plus pełne VERSION i COMPLETE_VERSION, które chciałeś. (Nie byłam pewna, co chciałeś dla numerów daty i czasu, więc wybrałam tylko połączone cyfry od daty i czasu.Możesz to łatwo zmienić.)

Po każdym uruchomieniu czyta się w build_num.h plik i analizuje go pod kątem numeru kompilacji; jeśli plik build_num.h nie istnieje, uruchamia on numer kompilacji na 1. Podobnie analizuje główne i podrzędne numery wersji, a jeśli plik nie istnieje, to domyślnie do wersji 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") 

Zrobiłem wszystkie definiuje tylko być liczbami całkowitymi, ale ponieważ są one proste całkowitymi można użyć standardowych sztuczek stringizing zbudować ciąg z nich, jeśli chcesz. Możesz także rozszerzyć go w sposób trywialny, aby utworzyć dodatkowe predefiniowane ciągi.

Ten program powinien działać poprawnie w wersji Python 2.6 lub nowszej, w tym w dowolnej wersji Python 3.x. Możesz uruchomić go w starym Pythonie z kilkoma zmianami, np. Nie używając .partition() do parsowania ciągu.

+0

Tak, mam 'Build Actions' Post and Pre. To dobry pomysł. I do zaakceptowania dla mnie. Mogę użyć dowolnej aplikacji, aby to zrobić. Poszedłem z prostą datą i czasem. Jedyną rzeczą jest "działanie budujące", które powinno być działaniem blokującym. Jeśli tak, to jest loteria. Dzięki za pomysł GR8. Ta odpowiedź jest również warta głosowania. Czy powinienem wybrać tę odpowiedź jako odpowiednią odpowiedź. Jest to inny rodzaj odpowiedzi poza wymiarami. Czekam na głosowanie jako odpowiedź. – Rick2047

+0

Do ciebie należy decyzja, czy przyjąć odpowiedź, czy nie. Myślę, że to pytanie miało niskie poglądy; niewielu ludzi nawet to widziało i jestem jedyną osobą, która do tej pory odpowiedziała. Być może będziesz musiał trochę poczekać, aż społeczność zareaguje na moją odpowiedź. – steveha

11

Oto działająca wersja "definicji kompilacji". Jest to podobne do mojej poprzedniej odpowiedzi, ale odkryłem miesiąc budowy. (Po prostu nie można obliczyć miesiąca kompilacji w instrukcji #if, ale można użyć wyrażenia trójskładnikowego, które zostanie skompilowane do stałej.)

Ponadto, zgodnie z dokumentacją, jeśli kompilator nie może uzyskać czasu w dniu, w którym otrzymasz znaki zapytania dla tych ciągów. Dodałem więc testy dla tego przypadku i sprawiłem, że różne makra zwracają oczywiście błędną wartość (99), jeśli tak się stanie.

#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 

z następującego kodu testowego, powyżej działa świetnie:

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

Jednak, gdy próbuję użyć tych makr z stringizing makro, to stringizes dosłowne wyrażenie! Nie wiem w żaden sposób, aby uzyskać kompilator do zmniejszenia wyrażenie do liczby całkowitej, a następnie stringize.

Ponadto, jeśli spróbujesz statycznie zainicjować tablicę wartości za pomocą tych makr, kompilator zgłosi problem z komunikatem error: initializer element is not constant. Nie możesz więc robić tego, co chcesz, za pomocą tych makr.

W tym momencie myślę, że najlepiej jest skrypt Python, który po prostu generuje nowy plik włączeń dla Ciebie. Możesz wstępnie skompilować wszystko, co chcesz w dowolnym formacie. Jeśli nie chcesz Pythona, możemy napisać skrypt AWK lub nawet program w języku C.

35

Jeśli możesz użyć kompilatora C++ do zbudowania pliku obiektu, który ma zawierać ciąg wersji, możemy zrobić dokładnie to, co chcesz! Jedyną magią jest to, że C++ pozwala używać wyrażeń do statycznego inicjowania tablicy, podczas gdy C nie. Wyrażenia muszą być w pełni obliczalne w czasie kompilacji, ale te wyrażenia są, więc nie stanowi to problemu.

Tworzymy ciąg znaków jeden bajt na raz i otrzymujemy dokładnie to, co chcemy.

// 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" 
//       

#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" 
//       

#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 
} 

To nie jest dokładnie format prosiłeś, ale wciąż nie w pełni zrozumieć, w jaki sposób chcesz dni i godziny odwzorowane do liczby całkowitej. Myślę, że to całkiem jasne, jak sprawić, by powstał jakikolwiek pożądany ciąg.

+0

Czy procesor rozwija wszystkie te makra - wszystkie instrukcje 'if' i operatory potrójne. Czy są one oceniane podczas kompilacji? –

+0

Oceniany podczas kompilacji, o ile wyrażenie używa tylko stałych danych znanych w czasie kompilacji, jak pokazano tutaj. – steveha

3

Krótka odpowiedź (wersja poproszony): (format 3.33.20150710.182906)

Proszę prosty Użyj makefile z:

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 

a jeśli nie chcesz makefile, jeszcze krócej , po prostu skompilować z:

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

Krótka odpowiedź (wersja sugerowane): (format +150.710,182906)

Użyj double dla numeru wersji:

Makefile:

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

Albo prosta komenda bash:

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

Wskazówka: Still don Czy podoba ci się makefile czy jest to tylko dla niezbyt małego programu testowego?Dodaj tę linię:

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

do ~/.profile i pamiętaj skompilować z gcc $CPPFLAGS ...


Długa odpowiedź:

Wiem, że to pytanie jest starszy, ale mam mały wkład robić. Najlepszą praktyką jest zawsze automatyzacja, co w przeciwnym razie może stać się źródłem błędu (lub zapomnienia).

Przywykłem do funkcji, która utworzyła dla mnie numer wersji. Ale wolę tę funkcję, aby zwrócić wartość float. Mój numer wersji może być wydrukowany przez: , która wydaje coś w rodzaju: 150710.150411 (jako Rok (2 cyfry) miesiąc dzień DOT godzina minuta sekund).

Ale, cóż, pytanie należy do ciebie. Jeśli wolisz "major.minor.date.time", musi to być ciąg znaków. (Zaufaj mi, podwójne jest lepsze.Jeśli nalegasz na majora, nadal możesz użyć podwójnego, jeśli ustawisz major i pozwól, aby ułamki dziesiętne były datami + czasem, np .: major.datetime = 1.150710150411

Przejdźmy do biznesu. będzie działać, jeśli kompilacji jak zwykle, zapominając, aby ustawić go lub użyj -DVERSION ustawić wersję bezpośrednio z powłoki, ale lepiej wszystkim polecam trzecią opcję: użyj makefile


trzy formy. kompilacja i wyniki:

Korzystanie zrobić:

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 

Bieg:

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

Korzystanie -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")\" 

Bieg:

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

Korzystanie z funkcji build-in:

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

Bieg:

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

kod źródłowy

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 

Należy pamiętać, że ciąg znaków jest ograniczony przez MAJOR<=9999 i MINOR<=9999. Oczywiście ustawiłem tę wysoką wartość, która, mam nadzieję, nigdy się nie przepełni. Ale używanie double jest jeszcze lepsze (plus, jest to całkowicie automatyczne, nie trzeba ręcznie ustawiać MAJOR i MINOR).

Teraz powyższy program jest nieco za duży. Lepiej jest całkowicie usunąć funkcję i zagwarantować, że makro VERSION jest zdefiniowane, albo przez -DVERSION bezpośrednio w wierszu poleceń GCC (lub alias, który automatycznie dodaje go, aby nie można było zapomnieć), lub zalecane rozwiązanie, aby uwzględnić ten proces w makefile.

Tu jest makefile używam: źródło


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] 

lepszą wersję z podwójnym

Teraz, kiedy przedstawiane ty "swoją" korzystne rozwiązanie, tutaj jest moje rozwiązanie:

skompilować z (a) makefile lub (b) gcc bezpośrednio:

(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) lub proste polecenia bash:

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

Kod źródłowy (wersja podwójna):

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

Uwaga: Ta podwójna funkcja istnieje tylko w przypadku, gdy zapomnisz zdefiniować makro WERSJA. Jeśli używasz makefile lub ustawisz alias gcc gcc -DVERSION=$(date +"%g%m%d.%H%M%S"), możesz bezpiecznie usunąć tę funkcję całkowicie.


Cóż, to wszystko. Bardzo schludny i łatwy sposób na skonfigurowanie kontroli wersji i nigdy więcej się nią nie przejmujesz!

+0

nigdy nie używaj zmiennej binarnej zmiennoprzecinkowej, jeśli chcesz dokładną reprezentację dziesiętną. – Javier

+0

Widzę twój punkt widzenia. Są sposoby na obejście, jeśli pojawi się jakaś runda. Używam tego formatu przez długi czas i nigdy nie miałem problemu. Poza tym jest łatwa do wykrycia i prawie do jej inokulum. Zgodziłbym się w nieco bardziej niebezpiecznej sytuacji. Nie tutaj. W każdym razie, proste zadanie ma zawierać trochę więcej zer na końcu, a następnie 5. "Wersja 1.1508122101150005". To z użyciem 'double' zamiast' float' byłoby wystarczające. Po prostu zignoruj ​​liczby po 12. miejscu dziesiętnym. To nie zmieni ostatniego (liczba względna sekund w tym przypadku). W każdym razie, miła obserwacja. –

0

to jest bardzo proste ....

[w make file]

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

OBJS = ....\

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

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

Data

DATA = $ (Shell + 'char szVersionStr [20] = "% m-Y%% d% H:% M:% s" ') < < == dodać

wszystkie wersja $ (ProgramID) < < wersja == dodać w pierwszym

wersji : < < == dodaj

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

[programem]

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

zewnętrzny znak szVersionStr [20];

[używając]

=== 4 ====

printf("Version: %s\n", szVersionStr); 
Powiązane problemy