如何在编译时检查像"#define VERSION 3.1.4"这样的值?

How to check a value like "#define VERSION 3.1.4" at compile time?

本文关键字:#define 编译 检查 VERSION      更新时间:2023-10-16

我正在为我公司的C++项目添加编译时检查,以确保所有开发机器和构建服务器上的第三方库都是最新的。大多数库对版本3.1.4

的定义如下:
#define VERSION_MAJOR 3
#define VERSION_MINOR 1
#define VERSION_BUILD 4

这很好,很容易使用 static_assert 或预处理器指令进行检查。

现在,我正在寻找一个定义单个宏的第三方库:

#define VERSION 3.1.4

如何在编译时验证此类宏的值?


使用 C++11,我可以使用constexpr字符串比较函数,并将宏字符串化以检查它:

constexpr bool static_equal(const char * a, const char * b)
{
    return (*a == *b) && (*a == '' || static_equal(a + 1, b + 1));
}
// stringification functions
#define str(x) #x
#define xstr(x) str(x)
static_assert(static_equal(xstr(VERSION), "3.1.4"), "incorrect version of libwhatever");

但是我们在Windows机器上使用Visual Studio 2013,所以我只能使用它支持的C++11的子集。很遗憾,不支持constexpr

这是我现在正在做的事情:

#define str(x) #x
#define xstr(x) str(x)
#include xstr(libwhatever.version.is.VERSION.should.be.3.1.4)

除此之外,我还向项目添加了一个名为 libwhatever.version.is.3.1.4.should.be.3.1.4 的空文件。因此,如果版本正确,预处理器将成功包含此文件。否则,它将失败,并显示"无法打开'libwhatever.version.is.2.7.2.should.be.3.1.4',没有这样的文件或目录"。最终,用某种有意义的消息使构建失败才是最重要的。

当然,这种方法不是很灵活;例如,我无法检查最小版本或一系列版本。但对我来说,能够检查确切的值就足够了。

这似乎适用于Visual C++和g ++。不过,我不确定该行为是否根据标准完全明确定义。

你不能在预处理器中,但你可以滥用类型特征!

VS 2013似乎支持可变参数模板。尝试在 https://stackoverflow.com/a/15912824/2097780 使用宏CSTRING(您应该能够将constexpr替换为const并且代码仍然有效)并执行以下操作:

#define STRT(x) decltype(CSTRING(x))
static_assert(std::is_same<STRT(VERSION), STRT("3.1.4")>::value, "incorrect version of libwhatever");

编辑:这行不通。但是,如果您的编译器编译此内容没有错误:

extern const char data[] = "abc";
template <char C> struct x {
    static const char c = C;
};
char buf[(int)x<"ABC123"[0]>::c];
int main() { return (int)buf; }

然后你可以试试这个:

#include <type_traits>
#define VERSION 1.2.3
#define STR2(x) #x
#define STR(x) STR2(x)
template <char...> struct ststring;
// https://stackoverflow.com/a/15860416/2097780
#define MACRO_GET_1(str, i) 
    (sizeof(str) > (i) ? str[(i)] : 0)
#define MACRO_GET_4(str, i) 
    MACRO_GET_1(str, i+0),  
    MACRO_GET_1(str, i+1),  
    MACRO_GET_1(str, i+2),  
    MACRO_GET_1(str, i+3)
#define MACRO_GET_16(str, i) 
    MACRO_GET_4(str, i+0),   
    MACRO_GET_4(str, i+4),   
    MACRO_GET_4(str, i+8),   
    MACRO_GET_4(str, i+12)
#define MACRO_GET_64(str, i) 
    MACRO_GET_16(str, i+0),  
    MACRO_GET_16(str, i+16), 
    MACRO_GET_16(str, i+32), 
    MACRO_GET_16(str, i+48)
#define MACRO_GET_STR(str) MACRO_GET_64(str, 0), 0
static_assert(std::is_same<ststring<MACRO_GET_STR(STR(VERSION))>,
                           ststring<MACRO_GET_STR("1.2.3")>>::value,
              "invalid library version");

如果右键单击项目->属性->生成事件->预构建事件您将看到一个显示"命令行"的选项。您可以在此处调用另一个程序。

您可以使用C++或您喜欢的任何语言编写另一个程序,以检查您的文件(或您想要的任意数量的文件)是否为"#define VERSION 3.1.4"。 您可以中止构建并在该程序中放置所需的任何警告。

这是一个教程:https://dillieodigital.wordpress.com/2012/11/27/quick-tip-aborting-builds-in-visual-studio-based-on-file-contents/

相关阅读: https://msdn.microsoft.com/en-us/library/e85wte0k.aspx

我尝试弄乱预处理器命令很长时间

了,但仅使用预处理器命令找不到一种方法。