Reputation: 650
I am writing a linked list implementation in C, and would like to use a language feature equivalent to C++'s templates to make my work easier.
Does such a feature exist?
Upvotes: 14
Views: 29541
Reputation: 13887
Take a look at this article.
C does not have static templates, but you can use macros to emulate them.
// 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);
"This template allows the code needed to define variables with basic type to be generalized and abstracted. The goal is to make code sharable and similar between types. However, this example is trivial in the sense it provides very little simplification over just writing out the statement. The real power comes from code that performs more complex tasks."
#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)
Upvotes: 1
Reputation: 62787
C has no templates like C++, though you can achieve something similar with "clever" (or WTFey, depending on how you look at it) use of #define
macros.
However, take a look at how for example GLib does it for singly linked lists or doubly linked lists.
Upvotes: 8
Reputation: 4035
If you use make
to build your software, one approach you may be able to use to achieve a similar result is to let make generate your code based on a template that you write, by calling something like sed or awk. I have used this approach many times and while it lacks the flexibility and features that C++ templates offer, it is extremely transparent (unlike macros), builds very efficiently, and requires no added tools apart from tried-and-true old-school unix utilities (e.g. make
and sed
). The main drawback is that you will specify your find/replace strings in a different location (a line in the Makefile) than your code.
Note that often, you would be better served by using function pointers and void pointers to just write a single code base that is versatile. However, if you want the additional performance from eliminating unnecessary function calls e.g. in tight loops, templates may be better and can be emulated as follows:
Write your template code, using placeholder names, with a template name such as code.template.c
Write your non-template code using function calls to your template code, after substituting in the appropriate names e.g. my_int_func()
or my_string_func()
Possibly, use an #include to include your template code in your non-template code (e.g. if your template will have inline
functions)
Write your Makefile to:
sed
is a good substitution tool, but you could also use e.g. replace
or awk
or any of their Windows equivalentsFor example:
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
build
make
This will generate printfuncs.generated.c (if that file doesn't exist or is less recently modified than code.template.c), which will look like:
/* 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);
}
Any compiler errors will point to this file, and you can either directly tinker with this file to get it to compile (after which you'll need to update your template to prevent your changes from being lost), or edit the template. In either case, after your edits, all you need to do is run make
to (try to) compile again.
run
./my_program
(or my_program.exe
if building on win)
Upvotes: 5
Reputation: 1587
hi i don't know about linked lists but for a template function u can probably use a macro or a function with varying number of arguments as an example this program
#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;
}
will produce the output
INT: 3
STR: baz
3 0
3.140000 0.500000
Upvotes: 1
Reputation: 2543
Templates are features of C++, but if you want a type-independent implementation of singly- or doubly-linked list, it can be made with help of macros, or you can simply store a void*
pointers in your structure.
Of course, there are lots of such implementations on the Internet. @MohamedKALLEL and @hyde already gave an examples from Linux kernel and from GLib, I would like just to add a note about nice little library uthash.
It implements a hash table in C, but it also has an utlist.h that implements singly- and doubly-linked (and even circular) lists entirely on macros. That is, you can simply take this file, include it and either use these macros as is, or modify it for your needs. Also nice is that you can use any of your datastructures with it: it only need to have next
pointer (and prev
, in case of doubly-linked).
P.s. But always remember when using macros: with great power comes great responsibility. Macros are powerful, but may become extremely unsafe and unreadable. Beware!
Upvotes: 5
Reputation: 43518
Yes there is list.h. And it's a circular linked list:
the following link contains an example of how to use it.
the list.h
contains all functions related to the management of a circular linked list like definition, add in the head , add in the tail , remove, foreach function to browse the circular linked list...
Upvotes: 3