2017-01-27 9 views
2

Мой вопрос похож на Different format of __DATE__ macro , но упомянутые там решения показывают ошибку в моем компиляторе VS 2013.Экстракт только год с даты макрос

Я хочу просто взять год часть от даты макроса, чтобы сделать макрос, который содержит строку, как

#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 COPY "Copyright" 

#define COMPANY "ABCD Lmtd" 

#define CYC BUILD_YEAR_CH0 BUILD_YEAR_CH1 BUILD_YEAR_CH2 COMPANY 

Так что я могу использовать макрос CYC для печати сцепленной строки везде, где обязательный.

Но как только я использую макрос/токен BUILD_YEAR_CH0 в макросе CYC, он показывает ошибку.

Я также попытался сделать константный буфер обугленного, который имеет точное значение года, как

const char MYEAR[] = { __DATE__[7], __DATE__[8],__DATE__[9],__DATE__[10],'\0' }; 

Но опять же, я не смог использовать его внутри макроса CYC. Неужели это невозможно сделать только с помощью макросов, не используя никаких переменных?

+0

Будет ли 'constexpr' или шаблон функции будет в порядке? –

+3

Зачем беспокоиться о боли, которая является макросами? Почему бы не написать правильную функцию? –

+0

@JesperJuhl Иногда вы хотите встроить компиляцию даты в двоичный файл. –

ответ

1

Макрос __DATE__ расширяется до 11-байтового строкового литерала с форматом "Mmm dd yyyy". Вы можете инициализировать указатель строки, чтобы указать на 8-й байт этого литерала, позже он может быть использован как строка 4 байта C с частью года компиляции. Этот указатель может быть локальным или глобальным, с автоматическим или статическим хранением:

#include <stdio.h> 

int main(void) { 
    const char *build_year = __DATE__ + 7; 

    printf("This program was compiled in %s\n", build_year); 
    return 0; 
} 

Вы можете даже использовать этот подход в макросе:

#define BUILD_YEAR (__DATE__ + 7) 

Примечание:

  • clang выдает предупреждение при компиляции вышеуказанного кода с -Weverything:

    ctyear.c:4:37: warning: expansion of date or time macro is not reproducible [-Wdate-time] 
    

    Вы можете отключить это предупреждение с помощью -Wno-date-time.

  • К сожалению, этот подход не может использоваться для других частей макроса __DATE__.


EDIT: Вы можете также определить макрос в Makefile. При таком подходе, вы имеете полный контроль над какими полями включить в расширении:

ctyear: ctyear.c 
    clang '-DBUILD_YEAR="$(shell date +%Y)"' $< -o [email protected] 

ctyear.c:

#include <stdio.h> 

#define COMPANY "Newco" 
#define CYC BUILD_YEAR " " COMPANY 

int main(void) { 
    printf("Copyright %s\n", CYC); 
    return 0; 
} 

Если у вас есть большой проект с большим количеством исходных файлов, вы, вероятно, у вас есть Makefile, и вы можете добавить '-DBUILD_YEAR="$(shell date +%Y)"' в определение CFLAGS.

+0

Привет, chqrlie, если вещи, где прямо, я бы прямо сделал что-то подобное, не публикуя здесь. Но здесь у меня много ограничений, этот макрос определен в файле заголовка и используется в нескольких местах внутри проекта. Мне нужно изменить существующую жестко закодированную часть и заменить ее так, чтобы все зависимые места были затронуты информацией года, после каждой компиляции – user7083883

+1

@ user7083883: соответствует ли макрос '#define MYEAR (__DATE__ + 7)' вашим ограничениям? – chqrlie

+0

И еще одно: я очень боюсь использовать такой указатель, как этот глобально, а не макрос. const char * myear = __DATE__ + 7; – user7083883

0

Код:

главный.с:

#include <stdio.h> 

#define STRINGIFY(s) # s 
#define EXPAND(s) STRINGIFY(s) 

#define COMPANY "ABCD Lmtd" 
#define CYC EXPAND(MYEAR) " " COMPANY 

int main(void) 
{ 
    printf("%s\n", CYC); 
} 

компиляции, как это:

gcc -Wall -Wextra -pedantic -Wconversion -g main.c -o main -DMYEAR=$(date +"%Y") 

Он печатает

2017 ABCD Lmtd 

Хотя я не понимаю, почему вы все равно, как дата наступает, если ее наконец-то доступен как макрос, вот еще один подход с использованием макроса __DATE__:

#define CYC strcat((char[4 + 1 + 1 + sizeof COMPANY]){__DATE__[7], __DATE__[8], __DATE__[9], __DATE__[10], ' ', '\0'}, COMPANY) 

или более гибкий

#define CYC(s) strcat((char[4 + 1 + 1 + sizeof (s)]){__DATE__[7], __DATE__[8], __DATE__[9], __DATE__[10], ' ', '\0'}, s) 
+0

Извините, как я уже сказал, это не связано с печатью даты моего проекта. Это огромный проект с графическим интерфейсом, который отображает это значение макроса CYC в нескольких местах меню GUI. В любом случае спасибо за ввод – user7083883

+0

Привет алк, я хочу упомянуть, я не могу просто использовать makefile здесь (начиная с VS 2013 proj). Во-вторых, я ошибочно упомянул в OP, что хочу напечатать дату, это не правильно. Текущий proj использует этот макрос для различных целей, таких как встраивание этой информации об авторских правах в различные элементы GUI e.t.c). Поскольку это проект GUI, здесь нет вывода на печать. Также я не совсем понял это: #define CYC (s) strcat ((char [4 + 1 + 1 + sizeof (s)]) {__ DATE __ [7], __DATE __ [8], __DATE __ [9], __DATE __ [ 10], '', '\ 0'}, s). Как это работает и как я могу его использовать? Не могли бы вы рассказать об этом? – user7083883

+0

@ user7083883: Как вы упомянули GUI: Требуется ли наличие строкового литерала (в отличие от того, что оценивается символом 'char *' -pointer), потому что '# define' ссылается на файл ресурсов Windows, '.rc'? – alk