【问题标题】:C macro parameter test at design time设计时的 C 宏参数测试
【发布时间】:2020-05-15 06:28:28
【问题描述】:

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

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

所以在这个例子中,有一个技巧可以在 PARAMETER > 24 bits 时强制 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");

    }

提前致谢!

【问题讨论】:

  • 所以你想要一个编译错误以防这个值太大?
  • 确切地说,我正在尝试使用 _Static_assert() 但到目前为止没有运气:)
  • 我不明白,如果MyMacro是一个函数,你会怎么写这个函数?
  • 查看我的回答,如果有帮助请告诉我
  • 哦,不幸的是,编译时变量的值是未知的..

标签: c macros


【解决方案1】:

不幸的是,_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 的不必要添加,因此不想使用它)。

【讨论】:

  • 我接受了你的建议,因为你为我指明了正确的方向 :) 再次感谢!
【解决方案2】:

好吧,我不想回复我自己的答案,但我想我找到了一个有效的解决方案(感谢@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() 将始终在 RUNTIME 返回 TRUE,但在 COMPILE 时,_Static_assert() 将捕获我的错误参数。

所以现在我可以使用了

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

希望我没有遗漏什么:)

【讨论】:

  • 表达式语句(即,将 () 放在复合语句(块)周围)是一种常见的扩展,但它们在技术上不是标准 C。它们也不能在文件范围内使用(除非 gcc 开发实现我的愿望:gcc.gnu.org/bugzilla/show_bug.cgi?id=93239) 和整数常量表达式。
【解决方案3】:

如果您需要在编译期间检查 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 在这里做什么?

【讨论】:

  • 确实如此,但我在应用程序中有很多计时器。将需要为每个人添加此检查,不是吗?我正在尝试签入(使用)我的宏本身
  • @orfruit 不,您在某个头文件中检查过一次。请解释variable在这里做什么??
  • @orfruit 或者告诉我们 MyMacro(variable,PARAMETER) 到底应该做什么。在您的问题中明确说明,edit your question
  • 请看用_Static_assert()编辑的,宏只是一个比较测试而已
猜你喜欢
  • 1970-01-01
  • 2015-10-19
  • 1970-01-01
  • 1970-01-01
  • 2012-12-18
  • 2012-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多