设计时的C宏参数测试

C macro parameter test at design time

我需要在设计时(预处理器)进行宏变量检查,更具体地说,该数字适合 24 位。 该宏旨在用于 if() 语句,所以我不知道如何测试它。

这是一个 ARM 系统定时器(24 位),很多时候我都忘记了#define 正确的值,尤其是在更改 MCU 时钟时,当然,我的 if() 从未触发,这个愚蠢的错误很难调试。

所以在这个例子中,有一个技巧可以在 PARAMETER > 24 位时强制 gcc 出错?

    #define PARAMETER   20000000  // over 24 bits, should throw a error at design time
    #define MyMacro(var, par)       (var > par)

    uint32_t variable;

    if(MyMacro(variable,PARAMETER))
    {
        // do something
        //  do something WRONG because PARAMETER > 24 bits


        // Actually this is working as expected, test for < is valid because 
// _Static_assert() is check for TRUE condition
// But I am still trying to find a way to combine this in original macro
        _Static_assert(PARAMETER < 0xFFFFFF, "Ooopss... ERROR");

    }

提前致谢!

如果您需要在编译期间检查 PARAMETER 是否 > 24 位,您可以简单地这样做:

#define PARAMETER   20000  // over 24 bits, should throw a error at design time
...
#if PARAMETER > (1<<24)
#error PARAMETER > 24 bits
#endif

你在这里做的不是编译时检查而是运行时间检查:

if(MyMacro(variable,PARAMETER))
{
    // do something
    //  do something WRONG because PARAMETER > 24 bits
}

但是如果您只是想知道 PARAMETER 是否大于 24 位,那么 variable 到底在做什么?

不幸的是,_Static_assert 在句法上被定义为声明,这意味着您不能直接在表达式内部使用它。

但是,无论如何都不需要 _Static_assert,因为您可以完美地(没有漂亮的编译时错误报告——但您是一名程序员,您应该能够找出编译时错误稍微更技术性的编译时错误消息)用

模拟它
#define static_assert_0expr(Truth) ((int)(0*sizeof(struct { int _ : (Truth)?1:-1; })))

(或等效项)并且您可以放入表达式(甚至是整数常量表达式)没问题:

#define static_assert_0expr(Truth) ((int)(0*sizeof(struct { int _ : (Truth)?1:-1; })))

#define PARAMETER   20000000  // over 24 bits, should throw a error at design time
#define MyMacro(var, par)       (static_assert_0expr((par)<0xffffff) + ((var) > (par)))

//or this, but this is won't preserve integer-constant expressions because of the comma:
/*#define MyMacro(var, par)       (static_assert_0expr((par)<0xffffff), ((var) > (par)))*/
//alternatively: (static_assert_0expr(assertion) ? (expr) : (expr)) is the most
//general form (though it leads to larger preprocessor expansions, which may worsen debugging experience with cc -E)

#include <stdint.h>
int main()
{
    static_assert_0expr(1)+1;
    uint32_t variable;

    if(MyMacro(variable,PARAMETER))
    {
    }
}

上面的static_assert_0expr宏也可以用_Static_assert实现:

#define static_assert_0expr(Truth) \
   ((int)(0*sizeof(struct { int _; _Static_assert(Truth,""); })))

或者您可以直接将其正文粘贴到 MyMacro 中并自定义消息(但我认为 _Static_assert 及其自定义编译时错误消息是对 C 的不必要添加,因此不希望使用它)。

好吧,我不想回复我自己的答案,但我想我找到了一个有效的解决方案(感谢@PSkoicik)并感谢 GCC 允许语句表达式(在这个回复中找到) Using and returning output in C macro

所以基本上 我可以在 if() 语句中使用 _Static_assert() 和辅助宏

#define CheckParameter(val) ({bool retval = true; _Static_assert((val)< 0xFFFFFF, "Timer value too large!"); retval;})

现在我的宏变成了

#define MyMacro(var, par)       ((var > par) && CheckParameter(par))

这应该有效,因为 CheckParameter() 在运行时总是 return TRUE,但在编译时,_Static_assert() 将捕获我的错误参数。

所以现在我可以使用

if(MyMacro(variable,PARAMETER))
{
// PAREMETER will be in range
}

希望我没有遗漏什么:)