我想知道在普通 C (C99) 中是否可以有一个包含可在条件表达式内使用的静态变量的宏。
我想出了以下内容(作为函数):
char EDGE(unsigned long x)
{
static char up = 0;
static unsigned long v;
if (up && v != x) {
v = x;
return 1;
} else {
v = x;
up = 1;
return 0;
}
}
这正是我想要的,只不过它只能工作一次(在使用另一个变量调用此函数时会错过缓存的值)。
所以我考虑了 C 中的宏,事实上,如果这可行的话,我可以免费获得一个变量缓存,而无需管理任何东西。使用普通的旧 C 语言是否可以实现这一点?
注意:我想要一个简单易用的边缘检测“函数”,可以在 if 语句中简单地调用它。
最佳答案
为此,您需要两个宏。第一个用于为特定变量设置边缘函数,第二个用于调用相关函数。
#include <stdio.h>
#define DEF_EDGE(var) static char edge##var(unsigned long var) \
{ \
static char up = 0; \
static unsigned long v = 0; \
if (up && v != var) { \
v = var; \
return 1; \
} else { \
v = var; \
up = 1; \
return 0; \
} \
}
#define EDGE(var) edge##var(var)
DEF_EDGE(x)
DEF_EDGE(y)
int main()
{
unsigned long x = 2, y = 3;
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
x=3;
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
y=4;
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
x=1; y=2;
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
return 0;
}
输出:
x=2, y=3 edge(x)=0, edge(y)=0
x=2, y=3 edge(x)=0, edge(y)=0
x=3, y=3 edge(x)=1, edge(y)=0
x=3, y=3 edge(x)=0, edge(y)=0
x=3, y=4 edge(x)=0, edge(y)=1
x=3, y=4 edge(x)=0, edge(y)=0
x=1, y=2 edge(x)=1, edge(y)=1
x=1, y=2 edge(x)=0, edge(y)=0
在每个宏中,##
是连接运算符。这将两个 token 合二为一。
当您在文件范围内使用第一个宏时:
DEF_EDGE(y)
这扩展为:
static char edgey(unsigned long var)
{
static char up = 0;
static unsigned long v = 0;
if (up && v != var) {
v = var;
return 1;
} else {
v = var;
up = 1;
return 0;
}
}
现在您有了一个可以检查 y
边缘条件的函数。
然后当您使用第二个宏时:
EDGE(y)
这扩展为:
edgey(y)
请注意,要使其发挥作用,您为其设置 EDGE 函数的每个变量都必须具有唯一的名称,无论范围如何。
编辑:
这是另一种没有范围问题的方法:
#include <stdio.h>
static char edge(unsigned long var, unsigned long *v)
{
if (*v != var) {
*v = var;
return 1;
} else {
*v = var;
return 0;
}
}
#define EDGE(var) edge(var, &var##_last)
#define SET_EDGE(var) \
unsigned long var##_last = var;
int main()
{
unsigned long x = 2, y = 3;
SET_EDGE(x);
SET_EDGE(y);
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
x=3;
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
y=4;
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
x=1; y=2;
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
printf("x=%lu, y=%lu edge(x)=%d, edge(y)=%d\n", x, y, EDGE(x), EDGE(y));
return 0;
}
在这种情况下,您可以在定义相关变量后立即调用 SET_EDGE
宏。这将创建另一个变量,其名称附加有 _last
,用于跟踪先前的值。当您使用 EDGE
mecro 时,此状态变量的地址将传递给 edge
函数。
关于包含静态变量作为条件的 C 宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43680991/