包含静态变量的C宏为条件

时间:2017-04-28 13:06:45

标签: c macros c-preprocessor

我想知道在普通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 -statement中简单地调用。

1 个答案:

答案 0 :(得分:3)

为此,您需要两个宏。第一个用于为特定变量设置边缘函数,第二个用于调用相关函数。

#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

在每个宏中,##是连接运算符。这将两个令牌合二为一。

在文件范围内使用第一个宏时:

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函数。