我正在使用C语言编写链表实现,希望使用一种类似于C++的模板的语言特性来使我的工作更简单。
是否存在这样的特性?
模板是C++的特性,但如果您想要一个独立于类型的单向或双向链表实现,可以借助宏来实现,或者您可以在结构中简单地存储void*
指针。
当然,在互联网上有很多这样的实现。 @MohamedKALLEL和@hyde已经从Linux内核和GLib给出了例子,我只想添加一个关于很好的小库uthash的注释。
它在C中实现了哈希表,但它也有一个utlist.h,它完全使用宏实现了单向和双向(甚至是循环)列表。也就是说,您可以简单地获取此文件,将其包含并使用这些宏,或者根据需要修改它。另外值得注意的是,您可以使用任何数据结构:它只需要具有next
指针(在双向链表的情况下还需要prev
)。
P.s. 但是请记住,使用宏时始终要牢记:伟大的力量伴随着巨大的责任。宏很强大,但可能变得极其不安全和难以阅读。小心!
make
来构建软件,您可以使用一种方法来实现类似的结果,即通过调用像sed或awk这样的工具,让make基于您编写的模板生成代码。我已经多次使用了这种方法,虽然它缺乏C++模板提供的灵活性和功能,但它非常透明(不像宏),构建效率很高,并且除了可靠的老式Unix工具(例如make
和sed
)之外,不需要添加任何工具。主要缺点是您将在不同位置(Makefile中的一行)指定查找/替换字符串,而不是在代码中。使用占位符名称编写模板代码,并使用模板名称(例如code.template.c)
使用函数调用您的模板代码编写非模板代码,替换适当的名称,例如my_int_func()
或my_string_func()
在需要时,使用#include在非模板代码中包含您的模板代码(例如,如果您的模板将具有inline
函数)
编写Makefile:
sed
是一个很好的替换工具,但您也可以使用例如replace
或awk
或它们的Windows等效工具/* 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
/* 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
(如果在win上构建,则为my_program.exe
)
只需进行很少的修改(删除列表项的硬件预取),我们也可以在我们的应用程序中使用此列表。 这个文件的可用版本可以在这里下载。
- MOHAMED请看这个文章。
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)
你好,我不了解链表,但对于模板函数,你可以使用宏或带有可变数量参数的函数作为示例。以下是一个程序:
#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