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

标签 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 语句中简单地调用它。

最佳答案

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

#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/

相关文章:

c - 在#define 之前使用#undef

css - LESS 导入不起作用

ios - 如何在不使用对象或类方法的情况下调用另一个类的变量?

c++ - 是否可以在编译时收集数据

c - 用于 C 模板仿真的 Doxygen

C - 如何通过窗口资源管理器(控制台)获取文件

c - 整体提升/转换:为什么我要关心结果类型的名称?

c - 将两个字符数组的值相加

c - K & R C 变量名称

android - 如何在android中创建MACROS