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