Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass a “Type” as a argument to function in c?

I want to write generic function (for example, function that get array in type of void** and doing something about this array) such then this function will get the type of the element (in the example, it's will be the type of any element in the array) as a argument.

Can I do it in c?


For example:

I want to write a function that get array (in type of void**) and initialize this array in some random way.

By "in some random way" I mean, for example a function that gets as arguments: array (in type void**) , the type of any element in the array, index (in type of int) and initialize this cell.

like image 968
AskMath Avatar asked May 21 '18 06:05

AskMath


Video Answer


4 Answers

This is only possible if you have a standard C compiler, in which case you can use the _Generic keyword for this purpose. You have to write a different function per supported type.

#include <stdio.h>

#define func(x) _Generic((x), int: func_int, char: func_char)(x);

void func_int (int x)
{
  printf("%s\t%d\n", __func__, x);
}

void func_char (char x)
{
  printf("%s\t%c\n", __func__, x);
}


int main(void)
{
  int i = 5;
  char c = 'A';

  func(i);
  func(c);
}

Output:

func_int        5
func_char       A
like image 53
Lundin Avatar answered Oct 22 '22 09:10

Lundin


Here's an example for for some macro trickery.

func.h

#ifndef FUNC_H
#define FUNC_H

#define add(a, b, typename) functionAdd##typename(a,b)

/* function declarations */
#define declared(typename) \
typename functionAdd##typename(typename, typename)

declared(int);
declared(float);

#endif

func.c

#include "func.h"

/* function code */
#define functionAdd(a, b, typename) \
typename functionAdd##typename(typename a, typename b){ \
    return a+b; \
}

/* function bodies (definitions) */
functionAdd(a, b, int)
functionAdd(a, b, float)

main.c

#include <stdio.h>
#include "func.h"

int main()
{
    int x1 = add(1, 2, int);
    float x2 = add(3.0, 4.0, float);
    printf("%d %f\n", x1, x2);  
    return 0;
}
like image 39
Stan Avatar answered Oct 22 '22 11:10

Stan


You don't pass the "type". C has no built-in way to encode and decode type information at runtime. The function operating on the objects must know the type statically. If you are absolutely intent on working with pointers to void, you have to delegate to a function that knows the type information. That can be done with a callback. For instance, the standard library function qsort accepts a callback for comparing the objects' values:

void qsort( void *ptr, size_t count, size_t size,
            int (*comp)(const void *, const void *) );

The calling code supplies the callback, and inside said callback it will cast back to the static type it needs to compare. That's how one usually works with pointers to void, one defines the set of operations it needs to do on the type in an abstract form, and then asks the calling code to supply an implementation for those operations.

like image 41
StoryTeller - Unslander Monica Avatar answered Oct 22 '22 09:10

StoryTeller - Unslander Monica


Another solution could be to define an enumeration to represent a type like this:

#include "stdio.h"

typedef enum {
    TYPE_INT,
    TYPE_CHAR,
    TYPE_STRING
} type_id;

int print(type_id type, void *data) {
    switch (type) {
    case TYPE_INT:
        // Do something with data as int
        printf("%d\n", * (int *)data);
        break;
    case TYPE_CHAR:
        // Do something with data as char
        printf("%c\n", * (char *)data);
        break;
    case TYPE_STRING:
        // Do something with data as string
        printf("%s\n", (char *)data);
        break;
    }
}

int main() {
    int a = 5;
    char b = 'a';
    char *c = "string";

    print(TYPE_INT, &a);
    print(TYPE_CHAR, &b);
    print(TYPE_STRING, c);

    return 0;
}

I like the suggestion by Lundin more as it provides type safety.

like image 36
PoVa Avatar answered Oct 22 '22 10:10

PoVa