我正在用C编写一个链表实现,并希望使用与C ++的 templates 相当的语言功能来使我的工作更轻松。
是否存在这样的功能?
答案 0 :(得分:6)
C没有像C ++这样的模板,尽管你可以使用#define
宏来实现与“聪明”(或WTFey,取决于你如何看待它)类似的东西。
但是,请查看GLib如何为singly linked lists或doubly 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实用程序外,不需要任何其他工具。 (例如make
和sed
)。主要缺点是您将在与代码不同的位置( Makefile 中的一行)指定查找/替换字符串。
请注意,通常,使用函数指针和void指针仅编写通用的单个代码库会更好。但是,如果您希望通过消除不必要的函数调用来提高性能,例如在紧密的循环中,模板可能会更好,并且可以如下模拟:
使用占位符名称和模板名称(例如 code.template.c
用适当的名称替换例如模板代码之后,使用对模板代码的函数调用来编写非模板代码。 my_int_func()
或my_string_func()
可能的话,请使用#include将模板代码包含在非模板代码中(例如,如果您的模板将具有inline
函数)
将您的Makefile写入:
sed
是很好的替代工具,但您也可以使用例如replace
或awk
或其任何Windows等效版本例如:
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(int, 0, 5, PRINT_INT)