C编程语言中有模板吗?

时间:2013-02-07 08:08:41

标签: c templates

我正在用C编写一个链表实现,并希望使用与C ++的 templates 相当的语言功能来使我的工作更轻松。

是否存在这样的功能?

6 个答案:

答案 0 :(得分:6)

C没有像C ++这样的模板,尽管你可以使用#define宏来实现与“聪明”(或WTFey,取决于你如何看待它)类似的东西。

但是,请查看GLib如何为singly linked listsdoubly linked lists执行此操作。

答案 1 :(得分:4)

模板是C ++的功能,但是如果你想要一个单独或双向链表的类型无关的实现,它可以在宏的帮助下完成,或者你可以简单地在你的void*指针存储结构

当然,互联网上有很多这样的实现。 @MohamedKALLEL@hyde已经提供了Linux内核和GLib的示例,我只想添加一个关于漂亮的小型库uthash的说明。

它在C中实现了一个哈希表,但它还有一个utlist.h,它在宏上实现了单个和双向链接(甚至是循环)列表完全。也就是说,您可以简单地获取此文件,包含它并按原样使用这些宏,或者根据您的需要对其进行修改。同样好的是你可以使用它的任何数据结构:它只需要next指针(和prev,如果是双重链接的话)。

P.S。但是在使用宏时要记住:强大的会带来很大的责任。宏是强大的,但可能变得非常不安全和不可读。当心!

答案 2 :(得分:3)

是的,有list.h。它是一个循环链表:

以下链接包含example如何使用它。

list.h包含与圆形链表管理相关的所有功能,如定义,添加在头部,添加尾部,删除,foreach函数来浏览循环链表......

答案 3 :(得分:1)

您好我不知道链接列表但是对于模板函数,您可以使用宏或具有不同数量参数的函数作为此程序的示例

#include <stdarg.h>
#include <stdio.h>
#define INT 0
#define STR 1
void foo( int type, ... )
{
    va_list ap;
    int i;
    char *s;
    va_start( ap, type );
    switch( type ) {
    case INT:
        i = va_arg( ap, int );
        printf( "INT: %i\n", i );
        break;
    case STR:
        s = va_arg( ap, char * );
        printf( "STR: %s\n", s );
        break;
    default:
        break;
    }
    va_end( ap );
}
#define SWAP( type, a, b ) {                    \
        type t;                                 \
        t = a;                                  \
        a = b;                                  \
        b = t;                                  \
    }
int main( void )
{
    foo( INT, 3 );
    foo( STR, "baz" );
    int ia = 0, ib = 3;
    SWAP( int, ia, ib );
    printf( "%i %i\n", ia, ib );
    float fa = 0.5, fb = 3.14;
    SWAP( float, fa, fb );
    printf( "%f %f\n", fa, fb );
    return 0;
}

将产生输出

INT: 3
STR: baz
3 0
3.140000 0.500000

答案 4 :(得分:1)

如果您使用make来构建软件,则可以使用一种获得相似结果的方法是,通过调用sed或w我已经使用了这种方法很多次,尽管它缺乏C ++模板提供的灵活性和功能,但它非常透明(与宏不同),构建效率很高,除了经过实践检验的老式unix实用程序外,不需要任何其他工具。 (例如makesed)。主要缺点是您将在与代码不同的位置( Makefile 中的一行)指定查找/替换字符串。

请注意,通常,使用函数指针和void指针仅编写通用的单个代码库会更好。但是,如果您希望通过消除不必要的函数调用来提高性能,例如在紧密的循环中,模板可能会更好,并且可以如下模拟:

  1. 使用占位符名称和模板名称(例如 code.template.c

  2. )来编写模板代码
  3. 用适当的名称替换例如模板代码之后,使用对模板代码的函数调用来编写非模板代码。 my_int_func()my_string_func()

  4. 可能的话,请使用#include将模板代码包含在非模板代码中(例如,如果您的模板将具有inline函数)

  5. 将您的Makefile写入:

    • 从template.c文件生成“实际” C文件。每个模板目标将有一个Makefile条目,例如 code.generation.c sed是很好的替代工具,但您也可以使用例如replaceawk或其任何Windows等效版本
    • 适当地,编译生成的C文件并链接生成的对象

例如:

code.template.c

/* Makefile will call sed to replace DATANAME, DATATYPE and SPECIFIER */
void print_DATANAME_data(DATATYPE x) {
  printf("%SPECIFIER\n", x);
}

code.c

#include <stdio.h>
#include "printfuncs.generated.c"

int main() {
  int i = 99;
  print_int_data(99);

  char *s = "hello";
  print_str_data(s);

  float f = 1.234;
  print_float_data(f);
}

Makefile

all: my_program

my_program: code.c
    CC -o $@ code.c

code.c: printfuncs.generated.c

printfuncs.generated.c: code.template.c
    rm -f printfuncs.generated.c
    cat code.template.c | sed 's/DATANAME/int/g;s/DATATYPE/int/g;s/SPECIFIER/i/g;' >> printfuncs.generated.c
    cat code.template.c | sed 's/DATANAME/str/g;s/DATATYPE/char */g;s/SPECIFIER/s/g;' >> printfuncs.generated.c
    cat code.template.c | sed 's/DATANAME/float/g;s/DATATYPE/float/g;s/SPECIFIER/f/g;' >> printfuncs.generated.c

构建

make

这将生成printfuncs.generation.c(如果该文件不存在或比code.template.c修改得少),如下所示:

/* Makefile will call sed to replace int, int and i */
void print_int_data(int x) {
  printf("%i", x);
}
/* Makefile will call sed to replace str, char * and s */
void print_str_data(char * x) {
  printf("%s", x);
}
/* Makefile will call sed to replace float, float and f */
void print_float_data(float x) {
  printf("%f", x);
}

任何编译器错误都将指向此文件,您可以直接修改此文件以进行编译(此后,您需要更新模板以防止所做的更改丢失),或编辑模板。无论哪种情况,编辑后,您都需要运行make来(尝试)再次编译。

运行

./my_program(或my_program.exe,如果以胜利为基础)

答案 5 :(得分:0)

看看这个article

C 没有静态模板,但您可以使用宏来模拟它们。

最简单的静态模板形式,定义宏:

// define a macro 
#define DEF(type, name, val) type name = val 
// call the macro 
DEF(int, foo, 5); 
// print the called macro 
printf("%d", foo);

"这个模板允许对定义基本类型变量所需的代码进行泛化和抽象。目标是使代码在类型之间可共享和相似。然而,这个例子是微不足道的,因为它只提供了很少的简化写出语句。真正的力量来自于执行更复杂任务的代码。”

这是您可以尝试的剪切和粘贴示例

#include <stdio.h>

int main()
{
#define FOREACH(type, start, end, fn)                                    \
    for (type _foreach_var = start; _foreach_var != end; _foreach_var++) \
    {                                                                    \
        fn(_foreach_var);                                                \
    }

#define PRINT_INT(n) printf("%d\n", n)
    // use FOREACH
    FOREACH(int, 0, 5, PRINT_INT)
}
  • 首先,我们定义 FOREACH 宏。
  • 然后我们可以使用它来循环,例如:FOREACH(int, 0, 5, PRINT_INT)