从日期宏中仅提取年份

Posted

技术标签:

【中文标题】从日期宏中仅提取年份【英文标题】:Extract only year from date macro 【发布时间】:2017-01-27 16:31:04 【问题描述】:

我的问题类似于Different format of __DATE__ macro 但提到的解决方案在我的 VS 2013 编译器中显示错误。

我只想从 date 宏中取出年份部分,以便制作一个包含类似

的字符串的宏
#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 宏来打印连接的字符串。

但是一旦我在 CYC 宏中使用 BUILD_YEAR_CH0 宏/令牌,它就会显示错误。

我也尝试过制作一个具有精确年份值的 const char 缓冲区,例如

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

但同样,我无法在 CYC 宏中使用它。 仅使用宏而不使用任何变量真的不可能做到这一点吗?

【问题讨论】:

constexpr 或模板函数可以吗? 为什么要为宏带来的痛苦烦恼呢?为什么不写一个合适的函数呢? @JesperJuhl 有时您想在二进制文件中嵌入编译日期。 A char 不会生成字符串。 将显示的代码传递给预处理器并检查其结果。 【参考方案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__ 宏的其他部分。


编辑:您还可以在 Makefile 中定义宏。使用这种方法,您可以完全控制要在扩展中包含哪些字段:

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

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 的定义中。

【讨论】:

嗨,chqrlie,如果事情这么简单,我会直接做这样的事情而不在这里发帖。但是在这里,我有很多限制,这个宏是在头文件中定义的,并且在项目中的几个地方使用。我需要修改现有的硬编码部分并替换它,以便在每次编译后所有依赖的地方都会受到年份信息的影响 @user7083883:宏 #define MYEAR (__DATE__ + 7) 是否符合您的限制条件? 还有一件事是,我非常害怕在全局范围内使用这样的指针而不是宏。 const char *myear = 日期 + 7; MYEAR/myear (对我来说)是一个非常令人困惑的名字。你的意思是MYYEAR/myear?现在它真的读起来像“我的耳朵”,很酷,但不是它的意思。还是这是除了我以外的所有人都知道的命名方案? 如果不是因为 CYC 被扩展为字符串文字预处理之后,你为什么坚持做#define CYC BUILD_YEAR COMPANY【参考方案2】:

如何使用此代码:

main.c:

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

【讨论】:

对不起,正如我所说,这与打印我的项目日期无关。这是一个巨大的项目,它有一个 GUI 输出,该 CYC 宏值显示在 GUI 菜单的多个位置。无论如何感谢您的输入 嗨,我想说的是,我不能在这里只使用makefile(自VS 2013 proj起)。第二件事是,我在 OP 中错误地提到我想打印日期,它不正确。当前项目将此宏用于各种目的,例如将此版权信息嵌入各种 GUI 项目等)。由于这是 GUI 项目,因此这里没有打印输出。我也不太明白:#define CYC(s) strcat((char[4 + 1 + 1 + sizeof (s)])__DATE__[7], __DATE__[8], __DATE__[9], __DATE__[ 10], ' ', '\0', s)。这是如何工作的,我该如何使用它?,你能说明一下吗? @user7083883:正如您提到的 GUI:您是否要求有可用的字符串文字(而不是评估为 char*-pointer 的东西),因为 #define 由windows资源文件,.rc? 没错,它被.rc使用了 #define MYEAR (DATE + 7) #define xstr(s) str(s) #define str(s) #s #define COPY "版权所有" #define COMPANY "ABCD Lmtd" #define YEAR COPY xstr(MYEAR) COMPANY o/p -> 版权所有("Jan 30 2017" + 7)ABCD Lmtd

以上是关于从日期宏中仅提取年份的主要内容,如果未能解决你的问题,请参考以下文章

从 r 中的日期中仅提取季度

从数据库中提取数据时如何在 GridView 中仅显示日期? C#

如何从日期字符串中提取年份?

如何从熊猫数据框中提取日期/年份/月份?

如何从 MDX 查询中提取日期中的月份年份

如何从python中不同类型的日期中提取年份