Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there templates in the C programming language?

Tags:

c

templates

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?

like image 406
fhuseynli Avatar asked Feb 07 '13 08:02

fhuseynli


People also ask

How many templates are there in C?

There are three kinds of templates: function templates, class templates and, since C++14, variable templates.

Is template a keyword in C?

C++ template is also known as generic functions or classes which is a very powerful feature in C++. A keyword “template” in c++ is used for the template's syntax and angled bracket in a parameter (t), which defines the data type variable.

Why do we use templates in C?

A template is a simple yet very powerful tool in C++. The simple idea is to pass data type as a parameter so that we don't need to write the same code for different data types. For example, a software company may need to sort() for different data types.

What is a programming template?

Program templates are common patterns of programming code usage that come up again and again as solutions to programming problems. A key skill in computer programming is learning to recognize these patterns and then applying them to unique situations.


4 Answers

Take a look at this article.

C does not have static templates, but you can use macros to emulate them.

simplest form of a static template, a definition macro:

// 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."

Here is a cut and paste example you can try out

#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)
}
  • First we define our FOREACH macro.
  • Then we can use it to loop such as here: FOREACH(int, 0, 5, PRINT_INT)
like image 67
jasonleonhard Avatar answered Oct 11 '22 23:10

jasonleonhard


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!

like image 23
NIA Avatar answered Oct 22 '22 14:10

NIA


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.

like image 7
hyde Avatar answered Oct 22 '22 13:10

hyde


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:

  1. Write your template code, using placeholder names, with a template name such as code.template.c

  2. 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()

  3. Possibly, use an #include to include your template code in your non-template code (e.g. if your template will have inline functions)

  4. Write your Makefile to:

    • Generate the "real" C files from the template.c files. You will have one Makefile entry per template target e.g. code.generated.c. sed is a good substitution tool, but you could also use e.g. replace or awk or any of their Windows equivalents
    • As appropriate, compile the generated C files and link the generated objects

For 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)

like image 4
mwag Avatar answered Oct 22 '22 14:10

mwag