设计时的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
}
希望我没有遗漏什么:)
我需要在设计时(预处理器)进行宏变量检查,更具体地说,该数字适合 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
}
希望我没有遗漏什么:)