I am getting back into using C, but I've been spoiled by generics in other languages. I have made it to the following piece of code in my implementation of a resizable array:
typdef struct {
void** array;
int length;
int capacity;
size_t type_size;
} Vector;
void vector_add(Vector* v, void* entry) {
// ... code for adding to the array and resizing
}
int main() {
Vector* vector = vector_create(5, sizeof(int));
vector_add(vector, 4); // This is erroneous...
// ...
}
In my attempt to make this generic, I'm now unable to add an integer to the vector without storing it in memory somewhere else.
Is there any way to make this work (either as is, or possibly a better approach to generics)?
For my answer I am assuming that you are not familiar with the sections of memory (ie the use of the memory pool).
In my attempt to make this generic, I'm now unable to add an integer to the vector without storing it in memory somewhere else.
If you want to create a generic structure (as you did) then you will need to use void pointers. Consequently, from the use of void pointers you will need to store the values for each field on the memory pool, or uncommonly on the stack. Note, the structure is composed of void pointers and hence only memory addresses are contained within the structure, pointing to other locations in memory where the values are.
Be careful if you declare them on the stack as once your stack frame is popped from the call stack those memory addresses are not considered to be valid and hence may be used by another stack frame (overwriting your existing values within that collection of memory addresses).
Aside: If you migrate to C++ then you can consider the use of C++ templates.
Yes; you can embrace Greenspun's Tenth Rule and develop a full blown dynamic language in C, and in the process, develop a relatively clean C run time that can be used from within C.
In this project I did just that, as have others before me.
In the C run time of this project, a generic number would be created from a C number like this:
val n = num(42);
because of the way val is represented, it takes up only a machine word. A few bits of type tag are used to distinguish a number from a pointer, from a character, etc.
There is also this:
val n = num_fast(42);
which is much faster (a bit manipulation macro) because it doesn't do any special checks that the number 42 fits into the "fixnum" range; it's used for small integers.
A function that adds its argument to every element of a vector could be written (very inefficiently) like this:
val vector_add(val vec, val delta)
{
val iter;
for (iter = zero; lt(iter, length(vec)); iter = plus(iter, one)) {
val *pelem = vecref_l(vec, iter);
*pelem = plus(*pelem, delta);
}
return nil;
}
Since plus is generic, this will work with fixnums, bignums and reals, as well as with characters, since it is possible to add integer displacements to characters via plus.
Type mismatch errors will be caught by the lower level functions and turned into exceptions. For instance if vec isn't something to which length can be applied, length will throw.
Functions with a _l suffix return a location. Wherease vecref(v, i) returns the value at offset i in vector v, vecref_l(v, i) returns a pointer to the val typed location in the vector which stores that value.
It's all C, just with the ISO C rules bent a little bit: you can't make a type like val efficiently in strictly conforming C, but you can do it quite portably to architectures and compilers you care about supporting.
Our vector_add isn't generic enough. It's possible to do better:
val sequence_add(val vec, val delta)
{
val iter;
for (iter = zero; lt(iter, length(vec)); iter = plus(iter, one)) {
val elem = ref(vec, iter);
refset(vec, iter, plus(elem, delta));
}
return nil;
}
By using the generic ref and refset, this now works with lists and strings also, not only vectors. We can do something like:
val str = string(L"abcd");
sequence_add(str, num(2));
The contents of str will change to cdef since a displacement of 2 is added to each character, in place.
Your idea can be done:
int *new_int = (int*)malloc(sizeof(int));
*new_int = 4;
vector_add(vector, new_int);
Naturally, it would be a good idea to do a int *create_int(int x) function or something similar:
int *create_int(int x)
{
int *n = (int*)malloc(sizeof(int));
*n = 4;
return n;
}
//...
vector_add(vector, create_int(4));
If your environment allows it you may consider using a well tested, widely used library that already manages all that, such as Glib. Or even C++.
You can avoid having many many small allocations by storing the data instead of pointers to it, like
typedef struct {
char* array;
int length;
int capacity;
size_t type_size;
} Vector;
bool vector_add(Vector* v, void* entry)
{
if (v->length < v->capacity || vector_expand(v)) {
char* location = v->array + (v->length++)*(v->type_size);
memcpy(location, entry, v->type_size);
return 1;
}
return 0; // didn't fit
}
int main()
{
Vector* vector = vector_create(5, sizeof(int));
int value = 4;
vector_add(vector, &value); // pointer to local is ok because the pointer isn't stored, only used for memcpy
}
Yes, here's an implementation of mine (similar to yours) that may help. It uses macros that can be wrapped with function calls for immediate values.
#ifndef VECTOR_H
# define VECTOR_H
# include <stddef.h>
# include <string.h>
# define VECTOR_HEADROOM 4
/* A simple library for dynamic
* string/array manipulation
*
* Written by: Taylor Holberton
* During: July 2013
*/
struct vector {
void * data;
size_t size, len;
size_t headroom;
};
int vector_init (struct vector *);
size_t vector_addc (struct vector *, int index, char c);
size_t vector_subc (struct vector *, int index);
// these ones are just for strings (I haven't yet generalized them)
size_t vector_adds (struct vector *, int index, int iend, const char * c);
size_t vector_subs (struct vector *, int ibegin, int iend);
size_t vector_addi (struct vector *, int index, int i);
size_t vector_subi (struct vector *, int index);
# define vector_addm(v, index, datatype, element) \
do { \
if (!v) return 0; \
\
if (!v->size){ \
v->data = calloc (v->headroom, sizeof (datatype)); \
v->size = v->headroom; \
} \
\
datatype * p = v->data; \
\
if (v->len >= (v->size - 2)){ \
v->data = realloc (v->data, \
(v->size + v->headroom) * sizeof (datatype)); \
p = v->data; \
memset (&p[v->size], 0, v->headroom * sizeof(datatype));\
v->size += v->headroom; \
} \
\
if ((index < 0) || (index > v->len)){ \
index = v->len; \
} \
\
for (int i = v->len; i >= index; i--){ \
p[i + 1] = p[i]; \
} \
\
p[index] = element; \
\
v->len++; \
\
} while (0)
# define vector_subm(v, index, datatype) \
do { \
if (!v || !v->len){ \
return 0; \
} \
\
if ((index < 0) || (index > (v->len - 1))){ \
index = v->len - 1; \
} \
\
datatype * p = v->data; \
\
for (int i = index; i < v->len; i++){ \
p[i] = p[i + 1]; \
} \
\
v->len--; \
\
if ((v->size - v->len) > v->headroom){ \
v->data = realloc (v->data, ((v->size - v->headroom) + 1) * sizeof (datatype));\
v->size -= v->headroom; \
} \
\
} while (0)
#endif
And I usually wrap them like:
size_t vector_addi (struct vector * v, int index, int i){
vector_addm (v, index, int, i);
return v->len;
}
I haven't had this code-reviewed, but I've been using it in a large program I'm writing and I haven't had any memory errors from them (using valgrind).
The only thing that is really missing (I've been meaning to add) the ability to add and subtract arrays from arrays.
Edit: I believe you can also do this same sort of thing with stdarg.h, but I've never tried it.
You asked for a better approach? Here ist is: https://github.com/m-e-leypold/glitzersachen-demos/tree/master/generix/v0-2011 (Disclosure: This is my code).
Let me explain very shortly:
I wanted type safe generic containers (which in other languages would be provided by proper generics (Ada) or parametric polymorphism (OCaml). This is the the feature that is most missing in C.
Macros just cannot do it (I'm not
going to explain that in detail. Suffice to say: The result of a template expansion or
generic instantiation should be a module in it's own right: In C this means, there are pre
processor symbols exported respectively can be used for module configuration (like
-DUSE_PROCESS_QUEUE_DEBUGCODE) you couldn't do that if you used C macros to generate
instances.
I'm abstracting over element type by moving element size and all relevant operation into a descriptive structure. This will be passed to every invocation of the generic code. Note that the descriptor describes the element type, so a descriptor instance will be needed once per generic instance.
I'm using a template processor to create a thin type safe frontend module to the generic code.
Example:
This is the prototype for the generic code to retrieve an element:
void fifo_get ( fifo_DESCRIPTOR* inst, fifo* , void* var );
This is the descriptor type:
typedef struct fifo_DESCRIPTOR {
size_t maxindex;
size_t element_size;
} fifo_DESCRIPTOR;
This is the template code in the type safe wrapper template:
<<eT>> <<>>get ( <<T>>* f ) {
<<eT>> e; fifo_get( &DESCRIPTOR, (fifo*) f, (void*) &e ); return e;
}
And this is what the template expander (instantiating an generic) produces from the template:
float floatq_get ( floatq* f ) {
float e; fifo_get( &DESCRIPTOR, (fifo*) f, (void*) &e ); return e;
}
All this has a nice make integration, but hardly any type safety in instantiation. Every error only crops up when compiling with cc.
I cannot justify at the moment, why to stick with source text templates in C instead of migrating to C++. For me, it was just an experiment.
Regards.
This approach will probably horrify you, but it can be made to work if you don't need any type-specialized logic:
// vector.h
#ifndef VECTOR_H
#define VECTOR_H
#define VECTOR_IMP(itemType) \
typedef struct { \
itemType * array; \
int length; \
int capacity; \
} itemType##_Vector; \
\
static inline void itemType##_vector_add(itemType##_Vector* v, itemType v) { \
// implementation of adding an itemType object to the array goes here \
} \
\
[... other static-inline generic vector methods would go here ...] \
// Now we can "instantiate" versions of the Vector struct and methods for
// whatever types we want to use.
VECTOR_IMP(int);
VECTOR_IMP(float);
VECTOR_IMP(char);
#endif
... and some example calling code:
#include "vector.h"
int main(int argc, char ** argv)
{
float_Vector fv = {0};
int_Vector iv = {0};
char_Vector cv = {0};
int_vector_add(&iv, 5);
float_vector_add(&fv, 3.14f);
char_vector_add(&cv, 'A');
return 0;
}
Instead of having the vector class store the added object, you could just return a pointer to the location where the caller can store it:
typdef struct {
char *buffer;
size_t length;
size_t capacity;
size_t type_size;
} Vector;
void *vector_add(Vector* v)
{
if (v->length == v->capacity) {
// ... increase capacity by at least one
// ... realloc buffer to capacity * type_size
}
return v->buffer + v->type_size * v->length++;
}
// in main:
*(int*)vector_add(v) = 4;
Using some non-standard GNU C extensions, it is possible to define generic functions with inferred parameter types. This macro defines a nested function in a statement expression and infers the parameter type using typeof:
#include <stdio.h>
#define fib(n1) ({\
typeof(n1) func(typeof(n1) n){\
if (n <= 1)\
return n;\
return func(n-1) + func(n-2);\
}\
func(n1);\
})
int main()
{
printf("%d\n",fib(3));
printf("%f\n",fib(3.0));
return 0;
}
Related
I have a Destination pointer stored in void* DestPointer and a source pointer stored in void* SrcPointer. Assume the destination pointer, points to starting adress of the free and safe memory and source pointer points to the starting adress of memory containing data it's type may be int16_t or int32_t) but can be interfered with counter i. Now I want to fill the memory by :
*(uint16_t*)DestPointer=*(uint16_t*) SrcPointer
I want this uint8_t change according to i, it could be a bounus if the stated problem generalizer to something like.
i==-1 -> int8_t
i==-2 -> int16_t
i==-4 -> int32_t
i==1 -> uint8_t
i==2 -> uint16_t
i==4 -> uint32_t
How to implement it? I just know enumeration can't work maybe some macro or magical c expression help.
It seems I need to implement memcpy() in a specific way!
Those strange indices aren't very helpful - it would have been much easier with adjacent numbers 0,1,2... So the best thing to do is to get rid of those negative numbers. Another good option would be to pick the copy size based on type with _Generic.
Otherwise assuming you can't change those index numbers... When dealing with bad interfaces that you are stuck with and can't change, X-macros might often be an ok solution. Something like this:
#define INT_TYPES(X) \
/* type val */ \
X(int8_t, -1) \
X(int16_t, -2) \
X(int32_t, -4) \
X(uint8_t, 1) \
X(uint16_t, 2) \
X(uint32_t, 4) \
Then create an enum eint8_t = -1, eint16_t = -2 and so on:
typedef enum
{
#define INT_TYPE_ENUM(type, val) e##type = (val),
INT_TYPES(INT_TYPE_ENUM)
} int_t;
Then a look-up table to compensate for the negative indices. This is using designated initializers so we get for example index [4 + -4] = sizeof(int32_t):
#define lookup_offset 4
const size_t int_type_lookup[] =
{
#define INT_TYPE_SIZE(type, val) [lookup_offset+(val)] = sizeof(type),
INT_TYPES(INT_TYPE_SIZE)
};
(Similarly you could make a function pointer look-up table which might be handy in some cases.)
The copy function which is a wrapper around memcpy:
void intcpy (void* restrict dst,
const void* restrict src,
size_t n,
int_t type)
{
memcpy(dst,src, n*int_type_lookup[lookup_offset + type]);
}
Complete example:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define INT_TYPES(X) \
/* type val */ \
X(int8_t, -1) \
X(int16_t, -2) \
X(int32_t, -4) \
X(uint8_t, 1) \
X(uint16_t, 2) \
X(uint32_t, 4) \
typedef enum
{
#define INT_TYPE_ENUM(type, val) e##type = (val),
INT_TYPES(INT_TYPE_ENUM)
} int_t;
void intcpy (void* restrict dst,
const void* restrict src,
size_t n,
int_t type)
{
#define lookup_offset 4
const size_t int_type_lookup[] =
{
#define INT_TYPE_SIZE(type, val) [lookup_offset+(val)] = sizeof(type),
INT_TYPES(INT_TYPE_SIZE)
};
memcpy(dst,src, n*int_type_lookup[lookup_offset + type]);
}
int main (void)
{
int16_t some_data [50]={1,2,3,4,5};
int16_t dst[50];
intcpy(dst, some_data, 50, eint16_t);
for(size_t i=0; i<5; i++)
{
printf("%d ", (int)dst[i]);
}
return 0;
}
I am fiddling around with an implementation of a generic dynamic array. The array should hold information about its size, how many entries are used, and then hold the actual data. The meta-information (size/used) is generic, but the data needs to handle different types, so I am handling that with macros. I am trying, however, to get the memory allocation code into functions. So my thought it is: I have a struct for meta-information
struct da_meta {
size_t size;
size_t used;
};
and then I have a macro that creates a struct per type, using a flexible array following the meta information:
#define dynarray(TYPE) \
struct { \
struct da_meta meta; \
TYPE data[]; \
}
I can declare an integer array, for example, as
dynarray(int) *int_array = 0;
To allocate and reallocate arrays, my thought was now to use code such as this:
#define size_overflow(meta_size, obj_size, len) \
((SIZE_MAX - meta_size) / obj_size < len)
// Always free if we cannot reallocate
void *realloc_dynarray_mem(void *p,
size_t meta_size,
size_t obj_size,
size_t new_len)
{
if (size_overflow(meta_size, obj_size, new_len))
goto abort;
struct da_meta *new_da =
realloc(p, meta_size + obj_size * new_len);
if (!new_da) goto abort;
new_da->size = new_len;
new_da->used = MIN(new_da->used, new_len);
return new_da;
abort:
free(p);
return 0;
}
The function gets the size of the struct sans the data objects, the size of individual objects, and the number of objects to allocate memory for. I don't use the size of the struct meta type, because it might be too small depending on the alignment of the data objects, but I will get it from sizeof the concrete (typed) structures. The function will always free the input and return NULL if I cannot allocate because in my application I have to give up if I cannot grow the array, so I don't try to preserve the old data in case there is an error.
There is nothing wrong with this code, as far as I can tell. I can always allocate memory, and as long as I have more than the size of struct meta, I can set the variables there. But when I return the result and use it as a dynarray(T) type, I am less sure. I think it should work, because C should put the memory of the first member of a struct first in a struct, and that is where I put struct meta, but am I right here?
I create a new array like this:
void *new_dynarray_mem(size_t meta_size,
size_t obj_size,
size_t len)
{
struct da_meta *array =
realloc_dynarray_mem(0, meta_size, obj_size, len);
if (array) {
// we do set size in realloc, but
array->size = len;
// if used was not initialised in realloc (and it wasn't)
// then we have to set it here...
array->used = 0;
}
return array;
}
#define new_da(type, init_size) \
new_dynarray_mem(sizeof(dynarray(type)), \
sizeof(type), init_size)
Here, the macro new_da() gets the size of the header/meta information from sizeof(dynarray(type)) and the size of the underlying types from sizeof(type). The second value is fine, but I am also uncertain about the first. Does the C standard guarantee that if I create two different structs with exactly the same code, e.g., calling dynarray(int) twice, that I get the same memory layout? I cannot imagine a compiler that would give me a different layout for the same code, but when it comes to imagining what compilers get up to, I am quite limited.
For appending to the array, I think all is fine. There I do not generate new types but get the size from the existing dynamic array, so if the first allocation is standard compliant, then I think the appending is as well, but I could be wrong.
#define da_free(da) \
do { free(da); da = 0; } while(0)
#define grow(size) \
(((size) == 0) ? /* special case for zero */ \
1 : \
((size) > SIZE_MAX / 2) ? /* can we grow? */ \
0 : /* no, then report size zero */ \
(2 * (size))) /* double the size */
#define da_append(da, ...) \
do { \
if (da->meta.used == da->meta.size) { \
size_t new_size = grow(da->meta.size); \
if (new_size == 0) { da_free(da); break; } \
da = realloc_dynarray_mem( \
da, sizeof *da, *da->data, new_size \
); \
if (!da) break; \
} \
da->data[da->meta.used++] = __VA_ARGS__; \
} while (0)
Am I guaranteed that if I lay out the concrete dynamic arrays with the meta-information at the top of the structs, then I can treat the allocate memory as both a pointer to the meta-information and the array? Is it safe to assume that I get the same size and memory layout if I generate the same struct twice? I feel that it must be that way since it shouldn't differ from if I include the same header file twice, but since I am generating the code there might be something that I am missing.
EDIT Based on the comments, I have updated the code to that below, but I have left the original code (of course) so the comments make sense in terms of that.
#define da_at(da,i) (da->data[(i)])
#define da_len(da) (da->meta.used)
struct da_meta {
size_t size;
size_t used;
};
#define dynarr(TYPE) \
struct { \
struct da_meta meta; \
TYPE data[]; \
}
// Always free if we cannot reallocate
void *realloc_dynarray_mem(struct da_meta *p,
size_t meta_size,
size_t obj_size,
size_t new_len)
{
// Size size overflow?
if (((SIZE_MAX - meta_size) / obj_size < new_len))
goto fail;
struct da_meta *new_da =
realloc(p, meta_size + obj_size * new_len);
if (!new_da) goto fail;
new_da->size = new_len;
new_da->used = MIN(new_da->used, new_len);
return new_da;
fail:
free(p);
return 0;
}
void *new_dynarray_mem(size_t meta_size,
size_t obj_size,
size_t len)
{
struct da_meta *array =
realloc_dynarray_mem(0, meta_size, obj_size, len);
if (array) array->used = 0;
return array;
}
void *grow_dynarray_mem(struct da_meta *p,
size_t meta_size,
size_t obj_size)
{
// Can we double the length?
size_t used = meta_size - obj_size * p->size;
size_t adding = MAX(1, p->size);
if ((SIZE_MAX - used) / obj_size < adding) {
free(p);
return 0;
}
return realloc_dynarray_mem(
p, meta_size, obj_size, p->size + adding
);
}
#define new_da(da, init_size) \
new_dynarray_mem(sizeof *(da), \
sizeof *(da)->data, \
(init_size))
#define da_free(da) \
do { free(da); da = 0; } while(0)
#define da_append(da, ...) \
do { \
if (da->meta.used == da->meta.size) { \
da = grow_dynarray_mem( \
(struct da_meta *)da, \
sizeof *da, sizeof *da->data \
); \
if (!da) break; \
} \
da->data[da->meta.used++] = __VA_ARGS__; \
} while (0)
When used, the code can look like this:
int main(void)
{
dynarr(int) *int_array = new_da(int_array, 0);
if (!int_array) goto error;
printf("%zu out of %zu\n",
int_array->meta.used,
int_array->meta.size);
for (int i = 0; i < 5; i++) {
da_append(int_array, i);
if (!int_array) goto error;
}
for (int i = 0; i < da_len(int_array); i++) {
printf("%d ", da_at(int_array, i));
}
printf("\n");
da_free(int_array);
return 0;
error:
return 1;
}
Just remember about padding between between meta and the start of the array and about alignment requirements and you should be fine.
because C should put the memory of the first member of a struct first in a struct, and that is where I put struct meta, but am I right here?
Yes.
Am I guaranteed that if I lay out the concrete dynamic arrays with the meta-information at the top of the structs, then I can treat the allocate memory as both a pointer to the meta-information
Yes, and...
and the array?
No. The array starts at address after meta + padding. So at address (char*)da + sizeof(dynarray(TYPE)) or just da->data.
Is it safe to assume that I get the same size and memory layout if I generate the same struct twice?
No and yes. There are many other great stackoverflow questions and answers about that topic - research them. Pragmatically yes, it would be a strange compiler that would would generate different padding for the same looking struct, but technically that's allowed.
using a flexible array
Unless you have specific aim, then I would just advise not to use them. It makes it harder for you to write the code. It makes it very hard to create and manage an array of such arrays.
goto abort;
What an unfortunate name for a goto label - abort() is a standard function.
#define grow(size)
Please use a prefix to all your library functions, especially macros. Defining such macro will make it impossible to use it in other code that happens to use a different grow() function. da_ seems like a good prefix.
I guess *da->data in realloc_dynarray_mem should be sizeof(*da->data).
#edit
I would suggest to use typeof keyword in new_da(). This would avoid specifying the type twice: in dynarray(TYPE) and in new_da(type, init_size). To make it, instead of passing the type, just pass the pointer on the dynamic array:
#define new_da(da, init_size) \
(da) = new_dynarray_mem(sizeof(dynarray(typeof(*(da)))), \
sizeof(typeof((da)->data[0])), (init_size))
Hence, this would avoid the mistake where the type used in the definition would differ from the type used in the allocation:
dynarray(int) *pInt;
pInt = new_da(char, 1024);
UPDATE FROM DISCUSSION IN COMMENTS:
And what about a single macro to define and initialize ?
#define new_da(da, type, init_size) \
dynarray(type) *da = new_dynarray_mem(sizeof(dynarray(type)), sizeof(type), init_size)
I would like this to work, but it does not:
#include <stdio.h>
typedef struct closure_s {
void (*incrementer) ();
void (*emitter) ();
} closure;
closure emit(int in) {
void incrementer() {
in++;
}
void emitter() {
printf("%d\n", in);
}
return (closure) {
incrementer,
emitter
};
}
main() {
closure test[] = {
emit(10),
emit(20)
};
test[0] . incrementer();
test[1] . incrementer();
test[0] . emitter();
test[1] . emitter();
}
It actually does compile and does work for 1 instance ... but the second one fails. Any idea how to get closures in C?
It would be truly awesome!
Using FFCALL,
#include <callback.h>
#include <stdio.h>
static void incrementer_(int *in) {
++*in;
}
static void emitter_(int *in) {
printf("%d\n", *in);
}
int main() {
int in1 = 10, in2 = 20;
int (*incrementer1)() = alloc_callback(&incrementer_, &in1);
int (*emitter1)() = alloc_callback(&emitter_, &in1);
int (*incrementer2)() = alloc_callback(&incrementer_, &in2);
int (*emitter2)() = alloc_callback(&emitter_, &in2);
incrementer1();
incrementer2();
emitter1();
emitter2();
free_callback(incrementer1);
free_callback(incrementer2);
free_callback(emitter1);
free_callback(emitter2);
}
But usually in C you end up passing extra arguments around to fake closures.
Apple has a non-standard extension to C called blocks, which do work much like closures.
The ANSI C has not a support for closure, as well as nested functions. Workaround for it is usage simple "struct".
Simple example closure for sum two numbers.
// Structure for keep pointer for function and first parameter
typedef struct _closure{
int x;
char* (*call)(struct _closure *str, int y);
} closure;
// An function return a result call a closure as string
char *
sumY(closure *_closure, int y) {
char *msg = calloc(20, sizeof(char));
int sum = _closure->x + y;
sprintf(msg, "%d + %d = %d", _closure->x, y, sum);
return msg;
}
// An function return a closure for sum two numbers
closure *
sumX(int x) {
closure *func = (closure*)malloc(sizeof(closure));
func->x = x;
func->call = sumY;
return func;
}
Usage:
int main (int argv, char **argc)
{
closure *sumBy10 = sumX(10);
puts(sumBy10->call(sumBy10, 1));
puts(sumBy10->call(sumBy10, 3));
puts(sumBy10->call(sumBy10, 2));
puts(sumBy10->call(sumBy10, 4));
puts(sumBy10->call(sumBy10, 5));
}
Result:
10 + 1 = 11
10 + 3 = 13
10 + 2 = 12
10 + 4 = 14
10 + 5 = 15
On C++11 it will be achived by use lambda expression.
#include <iostream>
int main (int argv, char **argc)
{
int x = 10;
auto sumBy10 = [x] (int y) {
std::cout << x << " + " << y << " = " << x + y << std::endl;
};
sumBy10(1);
sumBy10(2);
sumBy10(3);
sumBy10(4);
sumBy10(5);
}
A result, after compilation with a flag -std=c++11.
10 + 1 = 11
10 + 2 = 12
10 + 3 = 13
10 + 4 = 14
10 + 5 = 15
A Working Definition of a Closure with a JavaScript Example
A closure is a kind of object that contains a pointer or reference of some kind to a function to be executed along with the an instance of the data needed by the function.
An example in JavaScript from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures is
function makeAdder(x) {
return function(y) { // create the adder function and return it along with
return x + y; // the captured data needed to generate its return value
};
}
which could then be used like:
var add5 = makeAdder(5); // create an adder function which adds 5 to its argument
console.log(add5(2)); // displays a value of 2 + 5 or 7
Some of the Obstacles to Overcome with C
The C programming language is a statically typed language, unlike JavaScript, nor does it have garbage collection, and some other features that make it easy to do closures in JavaScript or other languages with intrinsic support for closures.
One large obstacle for closures in Standard C is the lack of language support for the kind of construct in the JavaScript example in which the closure includes not only the function but also a copy of data that is captured when the closure is created, a way of saving state which can then be used when the closure is executed along with any additional arguments provided at the time the closure function is invoked.
However C does have some basic building blocks which can provide the tools for creating a kind of closure. Some of the difficulties are (1) memory management is the duty of the programmer, no garbage collection, (2) functions and data are separated, no classes or class type mechanics, (3) statically typed so no run time discovery of data types or data sizes, and (4) poor language facilities for capturing state data at the time the closure is created.
One thing that makes something of a closure facility possible with C is the void * pointer and using unsigned char as a kind of general purpose memory type which is then transformed into other types through casting.
An update with new approach
My original posted answer seems to have been helpful enough that people have upvoted it however it had a constraint or two that I didn't like.
Getting a notification of a recent upvote, I took a look at some of the other posted answers and realized that I could provide a second approach that would overcome the problem that bothered me.
A new approach that removes a problem of the original approach
The original approach required function arguments to be passed on the stack. This new approach eliminates that requirement. It also seems much cleaner. I'm keeping the original approach below.
The new approach uses a single struct, ClosureStruct, along with two functions to build the closure, makeClosure() and pushClosureArg().
This new approach also uses the variable argument functionality of stdarg.h to process the captured arguments in the closure data.
Using the following in a C source code file requires the following includes:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <stdarg.h>
typedef struct {
void (*p)(); // pointer to the function of this closure
size_t sargs; // size of the memory area allocated for closure data
size_t cargs; // current memory area in use for closure data
unsigned char * args; // pointer to the allocated closure data area
} ClosureStruct;
void * makeClosure(void (*p)(), size_t sargs)
{
// allocate the space for the closure management data and the closure data itself.
// we do this with a single call to calloc() so that we have only one pointer to
// manage.
ClosureStruct* cp = calloc(1, sizeof(ClosureStruct) + sargs);
if (cp) {
cp->p = p; // save a pointer to the function
cp->sargs = sargs; // save the total size of the memory allocated for closure data
cp->cargs = 0; // initialize the amount of memory used
cp->args = (unsigned char *)(cp + 1); // closure data is after closure management block
}
return cp;
}
void * pushClosureArg(void* cp, size_t sarg, void* arg)
{
if (cp) {
ClosureStruct* p = cp;
if (p->cargs + sarg <= p->sargs) {
// there is room in the closure area for this argument so make a copy
// of the argument and remember our new end of memory.
memcpy(p->args + p->cargs, arg, sarg);
p->cargs += sarg;
}
}
return cp;
}
This code is then used similar to the following:
// example functions that we will use with closures
// funcadd() is a function that accepts a closure with two int arguments
// along with three additional int arguments.
// it is similar to the following function declaration:
// void funcadd(int x1, int x2, int a, int b, int c);
//
void funcadd(ClosureStruct* cp, int a, int b, int c)
{
// using the variable argument functionality we will set our
// variable argument list address to the closure argument memory area
// and then start pulling off the arguments that are provided by the closure.
va_list jj;
va_start(jj, cp->args); // get the address of the first argument
int x1 = va_arg(jj, int); // get the first argument of the closure
int x2 = va_arg(jj, int);
printf("funcadd() = %d\n", a + b + c + x1 + x2);
}
int zFunc(ClosureStruct* cp, int j, int k)
{
va_list jj;
va_start(jj, cp->args); // get the address of the first argument
int i = va_arg(jj, int);
printf("zFunc() i = %d, j = %d, k = %d\n", i, j, k);
return i + j + k;
}
typedef struct { char xx[24]; } thing1;
int z2func( ClosureStruct* cp, int i)
{
va_list jj;
va_start(jj, cp->args); // get the address of the first argument
thing1 a = va_arg(jj, thing1);
printf("z2func() i = %d, %s\n", i, a.xx);
return 0;
}
int mainxx(void)
{
ClosureStruct* p;
int x;
thing1 xpxp = { "1234567890123" };
p = makeClosure(funcadd, 256);
x = 4; pushClosureArg(p, sizeof(int), &x);
x = 10; pushClosureArg(p, sizeof(int), &x);
p->p(p, 1, 2, 3);
free(p);
p = makeClosure(z2func, sizeof(thing1));
pushClosureArg(p, sizeof(thing1), &xpxp);
p->p(p, 45);
free(p);
p = makeClosure(zFunc, sizeof(int));
x = 5; pushClosureArg(p, sizeof(int), &x);
p->p(p, 12, 7);
return 0;
}
The output from the above usage is:
funcadd() = 20
z2func() i = 45, 1234567890123
zFunc() i = 5, j = 12, k = 7
However there is an issue with the above implementation, you have no way of getting the return value of a function that returns a value. In other words, the function zFunc() used in a closure above returns an int value which is ignored. If you try to capture the return value with something like int k = pint->p(pint, 12, 7); you will get an error message because the function pointer argument of ClosureStruct is void (*p)(); rather than int (*p)();.
To work around this restraint, we will add two C Preprocessor macros to help us create individual versions of the ClosureStruct struct that specify a function return type other than void.
#define NAME_CLOSURE(t) ClosureStruct_ ## t
#define DEF_CLOSURE(t) \
typedef struct { \
t (*p)(); \
size_t sargs; \
size_t cargs; \
unsigned char* args; \
} NAME_CLOSURE(t);
We then redefine the two functions, zFunc() and z2func(), as follows using the macros.
DEF_CLOSURE(int) // define closure struct that returns an int
int zFunc(NAME_CLOSURE(int)* cp, int j, int k)
{
va_list jj;
va_start(jj, cp->args); // get the address of the first argument
int i = va_arg(jj, int);
printf("zFunc() i = %d, j = %d, k = %d\n", i, j, k);
return i + j + k;
}
typedef struct { char xx[24]; } thing1;
int z2func( NAME_CLOSURE(int) * cp, int i)
{
va_list jj;
va_start(jj, cp->args); // get the address of the first argument
thing1 a = va_arg(jj, thing1);
printf("z2func() i = %d, %s\n", i, a.xx);
return 0;
}
And we use this as follows:
int mainxx(void)
{
ClosureStruct* p;
NAME_CLOSURE(int) *pint;
int x;
thing1 xpxp = { "1234567890123" };
p = makeClosure(funcadd, 256);
x = 4; pushClosureArg(p, sizeof(int), &x);
x = 10; pushClosureArg(p, sizeof(int), &x);
p->p(p, 1, 2, 3);
free(p);
pint = makeClosure(z2func, sizeof(thing1));
pushClosureArg(pint, sizeof(thing1), &xpxp);
int k = pint->p(pint, 45);
free(pint);
pint = makeClosure(zFunc, sizeof(int));
x = 5; pushClosureArg(pint, sizeof(int), &x);
k = pint->p(pint, 12, 7);
return 0;
}
First Implementation With Standard C and a Bit of Stretching Here and There
NOTE: The following example depends on a stack based argument passing convention as is used with most x86 32 bit compilers. Most compilers also allow for a calling convention to be specified other than stack based argument passing such as the __fastcall modifier of Visual Studio. The default for x64 and 64 bit Visual Studio is to use the __fastcall convention by default so that function arguments are passed in registers and not on the stack. See Overview of x64 Calling Conventions in the Microsoft MSDN as well as How to set function arguments in assembly during runtime in a 64bit application on Windows? as well as the various answers and comments in How are variable arguments implemented in gcc? .
One thing that we can do is to solve this problem of providing some kind of closure facility for C is to simplify the problem. Better to provide an 80% solution that is useful for a majority of applications than no solution at all.
One such simplification is to only support functions that do not return a value, in other words functions declared as void func_name(). We are also going to give up compile time type checking of the function argument list since this approach builds the function argument list at run time. Neither one of these things that we are giving up are trivial so the question is whether the value of this approach to closures in C outweighs what we are giving up.
First of all lets define our closure data area. The closure data area represents the memory area we are going to use to contain the information we need for a closure. The minimum amount of data I can think of is a pointer to the function to execute and a copy of the data to be provided to the function as arguments.
In this case we are going to provide any captured state data needed by the function as an argument to the function.
We also want to have some basic safe guards in place so that we will fail reasonably safely. Unfortunately the safety rails are a bit weak with some of the work arounds we are using to implement a form of closures.
The Source Code
The following source code was developed using Visual Studio 2017 Community Edition in a .c C source file.
The data area is a struct that contains some management data, a pointer to the function, and an open ended data area.
typedef struct {
size_t nBytes; // current number of bytes of data
size_t nSize; // maximum size of the data area
void(*pf)(); // pointer to the function to invoke
unsigned char args[1]; // beginning of the data area for function arguments
} ClosureStruct;
Next we create a function that will initialize a closure data area.
ClosureStruct * beginClosure(void(*pf)(), int nSize, void *pArea)
{
ClosureStruct *p = pArea;
if (p) {
p->nBytes = 0; // number of bytes of the data area in use
p->nSize = nSize - sizeof(ClosureStruct); // max size of the data area
p->pf = pf; // pointer to the function to invoke
}
return p;
}
This function is designed to accept a pointer to a data area which gives flexibility as to how the user of the function wants to manage memory. They can either use some memory on the stack or static memory or they can use heap memory via the malloc() function.
unsigned char closure_area[512];
ClosureStruct *p = beginClosure (xFunc, 512, closure_area);
or
ClosureStruct *p = beginClosure (xFunc, 512, malloc(512));
// do things with the closure
free (p); // free the malloced memory.
Next we provide a function that allows us to add data and arguments to our closure. The purpose of this function is to build up the closure data so that when closure function is invoked, the closure function will be provided any data it needs to do its job.
ClosureStruct * pushDataClosure(ClosureStruct *p, size_t size, ...)
{
if (p && p->nBytes + size < p->nSize) {
va_list jj;
va_start(jj, size); // get the address of the first argument
memcpy(p->args + p->nBytes, jj, size); // copy the specified size to the closure memory area.
p->nBytes += size; // keep up with how many total bytes we have copied
va_end(jj);
}
return p;
}
And to make this a bit simpler to use lets provide a wrapping macro which is generally handy but does have limitations since it is C Processor text manipulation.
#define PUSHDATA(cs,d) pushDataClosure((cs),sizeof(d),(d))
so we could then use something like the following source code:
unsigned char closurearea[256];
int iValue = 34;
ClosureStruct *dd = PUSHDATA(beginClosure(z2func, 256, closurearea), iValue);
dd = PUSHDATA(dd, 68);
execClosure(dd);
Invoking the Closure: The execClosure() Function
The last piece to this is the execClosure() function to execute the closure function with its data. What we are doing in this function is to copy the argument list supplied in the closure data structure onto the stack as we invoke the function.
What we do is cast the args area of the closure data to a pointer to a struct containing an unsigned char array and then dereference the pointer so that the C compiler will put a copy of the arguments onto the stack before it calls the function in the closure.
To make it easier to create the execClosure() function, we will create a macro that makes it easy to create the various sizes of structs we need.
// helper macro to reduce type and reduce chance of typing errors.
#define CLOSEURESIZE(p,n) if ((p)->nBytes < (n)) { \
struct {\
unsigned char x[n];\
} *px = (void *)p->args;\
p->pf(*px);\
}
Then we use this macro to create a series of tests to determine how to call the closure function. The sizes chosen here may need tweaking for particular applications. These sizes are arbitrary and since the closure data will rarely be of the same size, this is not efficiently using stack space. And there is the possibility that there may be more closure data than we have allowed for.
// execute a closure by calling the function through the function pointer
// provided along with the created list of arguments.
ClosureStruct * execClosure(ClosureStruct *p)
{
if (p) {
// the following structs are used to allocate a specified size of
// memory on the stack which is then filled with a copy of the
// function argument list provided in the closure data.
CLOSEURESIZE(p,64)
else CLOSEURESIZE(p, 128)
else CLOSEURESIZE(p, 256)
else CLOSEURESIZE(p, 512)
else CLOSEURESIZE(p, 1024)
else CLOSEURESIZE(p, 1536)
else CLOSEURESIZE(p, 2048)
}
return p;
}
We return the pointer to the closure in order to make it easily available.
An Example Using the Library Developed
We can use the above as follows. First a couple of example functions that don't really do much.
int zFunc(int i, int j, int k)
{
printf("zFunc i = %d, j = %d, k = %d\n", i, j, k);
return i + j + k;
}
typedef struct { char xx[24]; } thing1;
int z2func(thing1 a, int i)
{
printf("i = %d, %s\n", i, a.xx);
return 0;
}
Next we build our closures and execute them.
{
unsigned char closurearea[256];
thing1 xpxp = { "1234567890123" };
thing1 *ypyp = &xpxp;
int iValue = 45;
ClosureStruct *dd = PUSHDATA(beginClosure(z2func, 256, malloc(256)), xpxp);
free(execClosure(PUSHDATA(dd, iValue)));
dd = PUSHDATA(beginClosure(z2func, 256, closurearea), *ypyp);
dd = PUSHDATA(dd, 68);
execClosure(dd);
dd = PUSHDATA(beginClosure(zFunc, 256, closurearea), iValue);
dd = PUSHDATA(dd, 145);
dd = PUSHDATA(dd, 185);
execClosure(dd);
}
Which gives an output of
i = 45, 1234567890123
i = 68, 1234567890123
zFunc i = 45, j = 145, k = 185
Well What About Currying?
Next we could make a modification to our closure struct to allow us to do currying of functions.
typedef struct {
size_t nBytes; // current number of bytes of data
size_t nSize; // maximum size of the data area
size_t nCurry; // last saved nBytes for curry and additional arguments
void(*pf)(); // pointer to the function to invoke
unsigned char args[1]; // beginning of the data area for function arguments
} ClosureStruct;
with the supporting functions for currying and resetting of a curry point being
ClosureStruct *curryClosure(ClosureStruct *p)
{
p->nCurry = p->nBytes;
return p;
}
ClosureStruct *resetCurryClosure(ClosureStruct *p)
{
p->nBytes = p->nCurry;
return p;
}
The source code for testing this could be:
{
unsigned char closurearea[256];
thing1 xpxp = { "1234567890123" };
thing1 *ypyp = &xpxp;
int iValue = 45;
ClosureStruct *dd = PUSHDATA(beginClosure(z2func, 256, malloc(256)), xpxp);
free(execClosure(PUSHDATA(dd, iValue)));
dd = PUSHDATA(beginClosure(z2func, 256, closurearea), *ypyp);
dd = PUSHDATA(dd, 68);
execClosure(dd);
dd = PUSHDATA(beginClosure(zFunc, 256, closurearea), iValue);
dd = PUSHDATA(dd, 145);
dd = curryClosure(dd);
dd = resetCurryClosure(execClosure(PUSHDATA(dd, 185)));
dd = resetCurryClosure(execClosure(PUSHDATA(dd, 295)));
}
with the output of
i = 45, 1234567890123
i = 68, 1234567890123
zFunc i = 45, j = 145, k = 185
zFunc i = 45, j = 145, k = 295
GCC and clang have the blocks extension, which is essentially closures in C.
GCC supports inner functions, but not closures. C++0x will have closures. No version of C that I'm aware of, and certainly no standard version, provides that level of awesome.
Phoenix, which is part of Boost, provides closures in C++.
On this page you can find a description on how to do closures in C:
http://brodowsky.it-sky.net/2014/06/20/closures-in-c-and-scala/
The idea is that a struct is needed and that struct contains the function pointer, but gets provided to the function as first argument. Apart from the fact that it requires a lot of boiler plate code and the memory management is off course an issue, this works and provides the power and possibilities of other languages' closures.
You can achieve this with -fblocks flag, but it does not look so nice like in JS or TS:
#include <stdio.h>
#include <stdlib.h>
#include <Block.h>
#define NEW(T) ({ \
T* __ret = (T*)calloc(1, sizeof(T)); \
__ret; \
})
typedef struct data_t {
int value;
} data_t;
typedef struct object_t {
int (^get)(void);
void (^set)(int);
void (^free)(void);
} object_t;
object_t const* object_create(void) {
data_t* priv = NEW(data_t);
object_t* pub = NEW(object_t);
priv->value = 123;
pub->get = Block_copy(^{
return priv->value;
});
pub->set = Block_copy(^(int value){
priv->value = value;
});
pub->free = Block_copy(^{
free(priv);
free(pub);
});
return pub;
}
int main() {
object_t const* obj = object_create();
printf("before: %d\n", obj->get());
obj->set(321);
printf("after: %d\n", obj->get());
obj->free();
return 0;
}
clang main.c -o main.o -fblocks -fsanitize=address; ./main.o
before: 123
after: 321
The idiomatic way of doing it in is C is passing a function pointer and a void pointer to the context.
However, some time ago I came up with a different approach. Surprisingly, there is a family of builtin types in C that carries both a data and the code itself. Those are pointers to a function pointer.
The trick is use this single object to pass both the code by dereferencing a function pointer. And next passing the very same double function pointer as the context as a first argument. It looks a bit convoluted by actually it results in very flexible and readable machanism for closures.
See the code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// typedefing functions makes usually makes code more readable
typedef double double_fun_t(void*, double);
struct exponential {
// closure must be placed as the first member to allow safe casting
// between a pointer to `closure` and `struct exponential`
double_fun_t *closure;
double temperature;
};
double exponential(void *ctx_, double x) {
struct exponential *ctx = ctx_;
return exp(x / ctx->temperature);
}
// the "constructor" of the closure for exponential
double_fun_t **make_exponential(double temperature) {
struct exponential *e = malloc(sizeof *e);
e->closure = exponential;
e->temperature = temperature;
return &e->closure;
}
// now simple closure with no context, a pure x -> x*x mapping
double square(void *_unused, double x){
(void)_unused;
return x*x;
}
// use compound literal to transform a function to a closure
double_fun_t **square_closure = & (double_fun_t*) { square };
// the worker that process closures, note that `double_fun_t` is not used
// because `double(**)(void*,double)` is builtin type
double somme(double* liste, int length, double (**fun)(void*,double)){
double poids = 0;
for(int i=0;i<length;++i)
// calling a closure, note that `fun` is used for both obtaing
// the function pointer and for passing the context
poids = poids + (*fun)(fun, liste[i]);
return poids;
}
int main(void) {
double list[3] = { 1, 2, 3 };
printf("%g\n", somme(list, 3, square_closure));
// a dynamic closure
double_fun_t **exponential = make_exponential(42);
printf("%g\n", somme(list, 3, exponential));
free(exponential);
return 0;
}
The advantage of this approach is that the closure exports a pure interface for calling double->double functions. There is no need to introduce any boxing structures used by all clients of the closure. The only requirement is the "calling convention" which is very natural and does not require sharing any code.
Answer
#include <stdio.h>
#include <stdlib.h>
/*
File Conventions
----------------
alignment: similar statements only
int a = 10;
int* omg = {120, 5};
functions: dofunction(a, b, c);
macros: _do_macro(a, b, c);
variables: int dovariable=10;
*/
////Macros
#define _assert(got, expected, teardownmacro) \
do { \
if((got)!=(expected)) { \
fprintf(stderr, "line %i: ", __LINE__); \
fprintf(stderr, "%i != %i\n", (got), (expected)); \
teardownmacro; \
return EXIT_FAILURE; \
} \
} while(0);
////Internal Helpers
static void istarted() {
fprintf(stderr, "Start tests\n");
}
static void iended() {
fprintf(stderr, "End tests\n");
}
////Tests
int main(void)
{
///Environment
int localvar = 0;
int* localptr = NULL;
///Closures
#define _setup_test(mvar, msize) \
do { \
localptr=calloc((msize), sizeof(int)); \
localvar=(mvar); \
} while(0);
#define _teardown_test() \
do { \
free(localptr); \
localptr=NULL; \
} while(0);
///Tests
istarted();
_setup_test(10, 2);
_assert(localvar, 10, _teardown_test());
_teardown_test();
_setup_test(100, 5);
_assert(localvar, 100, _teardown_test());
_teardown_test();
iended();
return EXIT_SUCCESS;
}
Context
I was curious about how others accomplished this in C. I wasn't totally surprised when I didn't see this answer. Warning: This answer is not for beginners.
I live a lot more in the Unix style of thinking: lots of my personal programs and libraries are small and do one thing very well. Macros as "closures" are much safer in this context. I believe all the organization and specified conventions for readability is super important, so the code is readable by us later, and a macro looks like a macro and a function looks like a function. To clarify, not literally these personal conventions, just having some, that are specified and followed to distinguish different language constructs (macros and functions). We all should be doing that anyway.
Don't do afraid of macros. When it makes sense: use them. The advanced part is the when. My example is one example of the whens. They are ridiculously powerful and not that scary.
Rambling
I sometimes use a proper closure/lambda in other languages to execute a set of expressions over and over within a function. It's a little context aware private helper function. Regardless of its proper definition, that's something a closure can do. It helps me write less code. Another benefit of this is you don't need to reference a struct to know how to use it or understand what it's doing. The other answers do not have this benefit, and, if it wasn't obvious I hold readability very highly. I strive for simple legible solutions. This one time I wrote an iOS app and it was wonderful and as simple as I could get it. Then I wrote the same "app" in bash in like 5 lines of code and cursed.
Also embedded systems.
I'm trying to create a function where parameters are passed as void pointers, and including a parameter setting the data type the void pointers will be cast to, so that the function may be used on different types. Something like the following, which does not work:
void test_function(int use_type, void * value, void * array) {
// Set types to the parameters based on 'use_type'
if (use_type == 0) { // Int type
int * valueT = (int *) value;
int * arrayT = (int *) array;
} else if (use_type == 1) { // Double type
double * valueT = (double *) value;
double * arrayT = (double *) array;
}
// Main code of the program, setting an array item, regardless of type
arrayT[0] = *valueT;
}
There are two problems with the above code: the properly typed valueT and arrayT are scoped in the conditional blocks and not visible to the main part of the code. Moving their declarations out of the blocks isn't viable in the given structure of the code though, as they would then need different names for int and double versions, defeating the whole idea of what I'm trying to achieve. The other problem is that valueT and arrayT are local to the function. What I really want is to set the parameter array: array[0] = *value.
It appears that what I'm trying to do isn't possible in C... Is there a way that this could be done?
EDIT:
The assignment to array line is there to demonstrate what I want to do, there is a lot more code in that part. There will also be a number of other types besides int and double. Moving the assignment line into the blocks would mean too much code duplication.
You're trying to implement polymorphism in C. Down this path lies madness, unmaintainable code, and new programming languages.
Instead, I strongly recommend refactoring your code to use a better method of working with mixed data. union or struct or pointers or any of the solutions here. This will be less work in the long run and result in faster and more maintainable code.
Or you can switch to C++ and use templates.
Or you can use somebody else's implementation like GLib's GArray. This is a system of clever macros and functions to allow easy access to any type of data in an array. It's Open Source so you can examine its implementation, a mix of macros and clever functions. It has many features like automatic resizing and garbage collection. And it is very mature and well tested.
A GArray remembers its type, so it isn't necessary to keep telling it.
GArray *ints = g_array_new(FALSE, FALSE, sizeof(int));
GArray *doubles = g_array_new(FALSE, FALSE, sizeof(double));
int val1 = 23;
double val2 = 42.23;
g_array_append_val(ints, val1);
g_array_append_val(doubles, val2);
The underlying plain C array can be accessed as the data field of the GArray struct. It's typed gchar * so it must be recast.
double *doubles_array = (double *)doubles->data;
printf("%f", doubles_array[0]);
If we continue down your path, the uncertainty about the type infects every "generic" function and you wind up writing parallel implementations anyway.
For example, let's write a function that adds two indexes together. Something which should be simple.
First, let's do it conventionally.
int add_int(int *array, size_t idx1, size_t idx2) {
return array[idx1] + array[idx2];
}
double add_double(double *array, size_t idx1, size_t idx2) {
return array[idx1] + array[idx2];
}
int main() {
int ints[] = {5, 10, 15, 20};
int value = add_int(ints, 1, 2);
printf("%d\n", value);
}
Taking advantage of token concatenation, we can put a clever macro in front of that to choose the correct function for us.
#define add(a, t, i1, i2) (add_ ## t(a, i1, i2))
int main() {
int ints[] = {5, 10, 15, 20};
int value = add(ints, int, 1, 2);
printf("%d\n", value);
}
The macro is clever, but probably not worth the extra complexity. So long as you're consistent about the naming the programmer can choose between the _int and _double form themselves. But it's there if you like.
Now let's see it with "one" function.
// Using an enum gives us some type safety and code clarity.
enum Types { _int, _double };
void *add(void * array, enum Types type, size_t idx1, size_t idx2) {
// Using an enum on a switch, with -Wswitch, will warn us if we miss a type.
switch(type) {
case _int : {
int *sum = malloc(sizeof(int));
*sum = (int *){array}[idx1] + (int *){array}[idx2];
return sum;
};
case _double : {
double *sum = malloc(sizeof(double));
*sum = (double *){array}[idx1] + (double *){array}[idx2];
return sum;
};
};
}
int main() {
int ints[] = {5, 10, 15, 20};
int value = *(int *)add((void *)ints, _int, 1, 2);
printf("%d\n", value);
}
Here we see the infection. We need a return value, but we don't know the type, so we have to return a void pointer. That means we need to allocate memory of the correct type. And we need to access the array with the correct type, more redundancy, more typecasting. And then the caller has to mess with a bunch of typecasting.
What a mess.
We can clean up some of the redundancy with macros.
#define get_idx(a,t,i) ((t *){a}[i])
#define make_var(t) ((t *)malloc(sizeof(t)))
void *add(void * array, enum Types type, size_t idx1, size_t idx2) {
switch(type) {
case _int : {
int *sum = make_var(int);
*sum = get_idx(array, int, idx1) + get_idx(array, int, idx2);
return sum;
};
case _double : {
double *sum = make_var(double);
*sum = get_idx(array, double, idx1) + get_idx(array, double, idx2);
return sum;
};
};
}
You can probably reduce the redundancy with even more macros, like Patrick's answer, but boy is this rapidly turning into macro hell. At a certain point you're no longer coding in C as you are rapidly expanding custom language implemented with stacks of macros.
Clifford's very clever idea of using sizes rather than types will not work here. In order to actually do anything with the values we need to know their types.
Once again, I cannot express strongly enough how big of a tar pit polymorphism in C is.
Instead of passing a type identifier, it is sufficient and simpler to pass the size of the object:
void test_function( size_t sizeof_type, void* value, void* array )
{
size_t element_index = 0 ; // for example
memcpy( (char*)array + element_index * sizeof_type, value, sizeof_type ) ;
}
In order to remain type-agnostic and maintain the flexibility of usage you appear to want, you'll need move your "main code" into a macro and call it for each case:
typedef enum {
USE_TYPE_INT = 0,
USE_TYPE_DOUBLE = 1,
// ...
} USE_TYPE;
void test_function(USE_TYPE use_type, void * value, void * array) {
#define TEST_FUNCTION_T(type) do { \
type * valueT = value; \
type * arrayT = array; \
/* Main code of the program */ \
arrayT[0] = *valueT; \
/* ... */ \
} while(0)
// Set types to the parameters based on 'use_type'
switch (use_type) {
case USE_TYPE_INT:
TEST_FUNCTION_T(int);
break;
case USE_TYPE_DOUBLE:
TEST_FUNCTION_T(double);
break;
// ...
}
#undef TEST_FUNCTION_T
}
Note that, while you only define the TEST_FUNCTION_T macro once, each usage will result in a duplicate code block differing only by the type pasted into the macro call when the program is compiled.
The direct answer to your question is do the assignment dereferencing in the block in which the pointers are valid:
void test_function(int use_type, void * value, void * array) {
// Set types to the parameters based on 'use_type'
if (use_type == 0) { // Int type
int * valueT = value, *arrayT = array; //the casts in C are unnecessary
arrayT[0] = *valueT;
} else if (use_type == 1) { // Double type
double * valueT = value, *arrayT = array;
arrayT[0] = *valueT;
}
}
but you should probably be doing this inline, without any type<->int translation:
(type*){array}[0] = *(type*){value} //could make it DRY with a macro
Is it possible to define a macro for the C preprocessor which takes an array as argument and expands to <type of array elements>_string? For example if x in an array of integers the macro invoked with argument x should expand to int_string.
I tried with
#define TypePaste(array) typeof(array[0])##_string
but it expands to )_string.
Even using multiple levels of indirection for the ## operand the macro doesn't expand correctly.
That's not possible. At the translation phase (the preprocessing phase) where macros are expanded and tokens are concatenated, the compiler (at this point, the preprocessor) does not yet have the notion of a type and thus cannot possibly generate types.
It is not all that clear what problem you are trying to solve, but given your comment:
the macro should expand to the name of an existing function. I'd like to define a function <type>_string for every existing type and then use the macro to select the right function according to the type of the array given.
Then you could use the C11 _Generic keyword:
#include <stdio.h>
void int_string (size_t size, int array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
void float_string (size_t size, float array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
#define TypePaste(array) \
_Generic( array, \
int: int_string, \
float: float_string ) \
(sizeof(array)/sizeof(*array), array) // function parameters
int main()
{
int i_arr[5];
float f_arr[3];
TypePaste(i_arr);
TypePaste(f_arr);
}
Output:
I am int_string, do stuff here.
I am float_string, do stuff here.
Note: this assumes that the passed parameter is a local/file scope allocated array. If passing a pointer, there's no type safety and the program will fail.
C11's _Generic type selection is the "proper" way to do what you want. There are other, platform dependent solutions, tough.
If you are using gcc – you don't say so eplicitly, but you use gcc's extension typeof already – you can use gcc's statement expresions and nested functions to create a comparison function for qsort on the spot:
double a[5] = {8.4, 8.1, 9.3, 12.2, 5.2};
qsort(a, 5, sizeof(*a), ({
int cmp(const void *p, const void *q) {
const typeof(a[0]) *pp = p;
const typeof(a[0]) *qq = q;
return (*pp < *qq) ? -1 : (*pp > *qq);
}
cmp;
}));
This creates a function and returns its address. (The last statement of a compound expression is its value. The scope of the local variables is the statement expression, but a nested function is not created on the stack so its safe to return a pointer to that function.)
For primitive types, where you want to sort according to the comparison operators < and >, you can turn that into a macro:
#define COMPARE(ARRAY)({ \
int cmp(const void *p, const void *q) { \
const typeof(ARRAY[0]) *pp = p; \
const typeof(ARRAY[0]) *qq = q; \
return (*pp < *qq) ? -1 : (*pp > *qq); \
} \
cmp; \
})
qsort(a, 5, sizeof(*a), COMPARE(a));
or even:
#define SORT(ARRAY, N) \
qsort(ARRAY, N, sizeof(*ARRAY), COMPARE(ARRAY))
SORT(a, 5);
That's not Standard C, so if you need compatibility between platforms, this is out of the question.