在C中使用typedef创建泛型

时间:2014-11-09 19:24:25

标签: c pointers generics types typedef

我现在正在C中做我的hw,我们在讲座中给出了以下代码来创建泛型类型。在C ++中,我知道你可以通过使用模板来实现这一点。我们的导师希望我们使用这些(所以现在我没有想到没有空虚*)。 但是,我对如何宣布这一点感到困惑。

typedef struct Cell(x) *List(x);

struct Cell(x) {
   x* data;
   List(x) next;
};

所以,我知道编译器看到的时候     列表(x)      它会在struct Cell(x)中替换,所以我尝试做List(int)a;在main()中,但是没有工作

2 个答案:

答案 0 :(得分:3)

新版本的C添加了“类型通用表达式”,允许例如abs函数使用不同的参数类型执行不同的操作。

但据我所知,仍然没有通用类型。您对实现集合类型的选择:

  1. 使用void*
  2. 放弃类型安全
  3. 输入每种元素类型的集合/容器代码。
  4. 使用宏生成与#2相同的代码。
  5. 我怀疑你打算做#3。有点像:

    #define Cell(x) specialized_##x##_Cell
    #define List(x) specialized_##x##_List
    
    #define SINGLY_LINKED_LIST(x) \\
         typedef struct Cell(x) *List(x); \\
         struct Cell(x) \\
         { \\
              x* data; \\
              List(x) next; \\
         };
    

    然后你可以像

    一样使用它
    SINGLY_LINKED_LIST(int)
    
    int main(void)
    {
        List(int) a;
    }
    

答案 1 :(得分:0)

有一种方法可以伪造C等带有宏的容器等模板。您必须编写两个生成声明的宏,以及新结构类型的定义以及作用于此类型的函数。

例如,对于(不完整的)列表类型:

#define DECLARE_LIST(T_Name, T_Tag, T_Type)         \
                                                    \
    typedef struct T_Name##Node T_Name##Node;       \
    typedef struct T_Name T_Name;                   \
                                                    \
    struct T_Name {                                 \
        T_Name##Node *head;                         \
        T_Name##Node *tail;                         \
        int count;                                  \
    };                                              \
                                                    \
    struct T_Name##Node {                           \
        T_Type value;                               \
        T_Name##Node *next;                         \
    };                                              \
                                                    \
    int T_Tag##_init(T_Name *ll);                   \
    int T_Tag##_free(T_Name *ll);                   \
    int T_Tag##_add(T_Name *ll, T_Type x);

#define DEFINE_LIST(T_Name, T_Tag, T_Type)          \
                                                    \
    int T_Tag##_init(T_Name *ll)                    \
    {                                               \
        ll->head = ll->tail = NULL;                 \
        ll->count = 0;                              \
        return 0;                                   \
    }                                               \
                                                    \
    int T_Tag##_free(T_Name *ll)                    \
    {                                               \
        while (ll->head) {                          \
            T_Name##Node *next = ll->head->next;    \
            free(ll->head);                         \
            ll->head = next;                        \
        }                                           \
        return 0;                                   \
    }                                               \
                                                    \
    int T_Tag##_add(T_Name *ll, T_Type x)           \
    {                                               \
        T_Name##Node *nd = malloc(sizeof(*nd));     \
                                                    \
        if (nd == NULL) return -1;                  \
        nd->next = NULL;                            \
        nd->value = x;                              \
                                                    \
        if (ll->head == NULL) {                     \
            ll->head = ll->tail = nd;               \
        } else {                                    \
            ll->tail->next = nd;                    \
            ll->tail = nd;                          \
        }                                           \
        ll->count++;                                \
                                                    \
        return 0;                                   \
    }

#define IMPLEMENT_LIST(T_Name, T_Tag, T_Type)       \
    DECLARE_LIST(T_Name, T_Tag, T_Type)             \
    DEFINE_LIST(T_Name, T_Tag, T_Type)              \

如果要声明新的列表类型,则应在标头中DECLARE_LIST和C源中的DEFINE_LIST。如果类型是编译模块的私有类型,则可以将IMPLEMENT_LIST放在C源代码中。

(宏是不完整的,因为它只为该类型实现了三个函数,这些函数本身没用。这只是为了显示基本的工作原理。你通常会得到两个巨大的宏。)

您可以像这样使用宏:

IMPLEMENT_LIST(Intlist, il, int)
IMPLEMENT_LIST(Stringlist, sl, char *)

这会创建两个新的列表类型IntlistStringlist,以及相应的函数,前缀为il_sl_,您可以像其他函数一样使用它们:< / p>

int main()
{
    Intlist il;
    Stringlist sl;

    il_init(&il);
    sl_init(&sl);

    il_add(&il, 1);
    il_add(&il, 2);
    il_add(&il, 5);

    sl_add(&sl, "Hello");
    sl_add(&sl, "World");

    // ... more stuff ...

    il_free(&il);
    sl_free(&sl);

    return 0;
}

此方法是类型安全的:例如,您无法将Stringlist传递给il函数。因为代码只包含宏,所以可以在头文件中实现它。

但是有一些限制:

  • 作业是=。这意味着例如字符串列表不能将副本保存在char数组中。如果客户端代码复制数据,则清理代码不知道它。您可以通过将复制,比较,构造函数和析构函数(也可以是宏)指定为宏参数来满足此类情况,但这很快就会变得复杂。

  • 有“秘密”类型名称涉及上例中的节点类型。它们必须是有效的标识符(而不是C ++,编译器会创建mangles名称),这可能会导致令人惊讶的名称冲突。

  • 使用私有实现时,函数不应该是static

它的优势在于,Stringlist的名称比std::list<std::string>更好。