303

Is there any way to achieve function overloading in C? I am looking at simple functions to be overloaded like

foo (int a)  
foo (char b)  
foo (float c , int d)

I think there is no straight forward way; I'm looking for workarounds if any exist.

Gaurang Tandon
  • 6,504
  • 11
  • 47
  • 84
FL4SOF
  • 4,161
  • 6
  • 28
  • 24
  • 9
    Why would you want to do this? C has no polymorphic abilities. So foo(random type) is impossible. Just make real funcs foo_i, foo_ch, foo_d, etc. – jmucchiello Jan 26 '09 at 13:10
  • 8
    You can go the evil way using void pointers and type ids. – alk Oct 20 '11 at 09:28
  • 19
    I feel I should draw attention to the fact that the answer to this question [has changed since it was originally asked](http://stackoverflow.com/a/25026358/1366431), with the new C standard. – Alex Celeste Sep 07 '14 at 00:05

16 Answers16

320

Yes!

In the time since this question was asked, standard C (no extensions) has effectively gained support for function overloading (not operators), thanks to the addition of the _Generic keyword in C11. (supported in GCC since version 4.9)

(Overloading isn't truly "built-in" in the fashion shown in the question, but it's dead easy to implement something that works like that.)

_Generic is a compile-time operator in the same family as sizeof and _Alignof. It is described in standard section 6.5.1.1. It accepts two main parameters: an expression (which will not be evaluated at runtime), and a type/expression association list that looks a bit like a switch block. _Generic gets the overall type of the expression and then "switches" on it to select the end result expression in the list for its type:

_Generic(1, float: 2.0,
            char *: "2",
            int: 2,
            default: get_two_object());

The above expression evaluates to 2 - the type of the controlling expression is int, so it chooses the expression associated with int as the value. Nothing of this remains at runtime. (The default clause is optional: if you leave it off and the type doesn't match, it will cause a compilation error.)

The way this is useful for function overloading is that it can be inserted by the C preprocessor and choose a result expression based on the type of the arguments passed to the controlling macro. So (example from the C standard):

#define cbrt(X) _Generic((X),                \
                         long double: cbrtl, \
                         default: cbrt,      \
                         float: cbrtf        \
                         )(X)

This macro implements an overloaded cbrt operation, by dispatching on the type of the argument to the macro, choosing an appropriate implementation function, and then passing the original macro argument to that function.

So to implement your original example, we could do this:

foo_int (int a)  
foo_char (char b)  
foo_float_int (float c , int d)

#define foo(_1, ...) _Generic((_1),                                  \
                              int: foo_int,                          \
                              char: foo_char,                        \
                              float: _Generic((FIRST(__VA_ARGS__,)), \
                                     int: foo_float_int))(_1, __VA_ARGS__)
#define FIRST(A, ...) A

In this case we could have used a default: association for the third case, but that doesn't demonstrate how to extend the principle to multiple arguments. The end result is that you can use foo(...) in your code without worrying (much[1]) about the type of its arguments.


EDIT Cosinus has a much more elegant solution for multi-argument overloads that works with C23 or GNU extensions, the technique below was written against C11 (which didn't really want to let you do this).

For more complicated situations, e.g. functions overloading larger numbers of arguments, or varying numbers, you can use utility macros to automatically generate static dispatch structures:

void print_ii(int a, int b) { printf("int, int\n"); }
void print_di(double a, int b) { printf("double, int\n"); }
void print_iii(int a, int b, int c) { printf("int, int, int\n"); }
void print_default(void) { printf("unknown arguments\n"); }

#define print(...) OVERLOAD(print, (__VA_ARGS__), \
    (print_ii, (int, int)), \
    (print_di, (double, int)), \
    (print_iii, (int, int, int)) \
)

#define OVERLOAD_ARG_TYPES (int, double)
#define OVERLOAD_FUNCTIONS (print)
#include "activate-overloads.h"

int main(void) {
    print(44, 47);   // prints "int, int"
    print(4.4, 47);  // prints "double, int"
    print(1, 2, 3);  // prints "int, int, int"
    print("");       // prints "unknown arguments"
}

(implementation here) So with some effort, you can reduce the amount of boilerplate to looking pretty much like a language with native support for overloading.

As an aside, it was already possible to overload on the number of arguments (not the type) in C99.


[1] note that the way C evaluates types might trip you up though. This will choose foo_int if you try to pass it a character literal, for instance, and you need to mess about a bit if you want your overloads to support string literals. Still overall pretty cool though.

Alex Celeste
  • 12,824
  • 10
  • 46
  • 89
  • 1
    Based on your example it looks like the only thing being overloaded is function like macros. Let me see if I understand correctly: If you want to overload functions you'd just be using the preprocessor to divert the function call based on the data types passed in, right? – Nick Feb 05 '15 at 17:47
  • Alas, whenever C11 begins to catch on I assume MISRA will not embrace this feature for the same reasons they forbid variable arguments lists. I try to stick by MISRA pretty close in my world. – Nick Feb 05 '15 at 17:50
  • 12
    @Nick that's all overloading is. It's just handled implicitly in other languages (e.g. you can't really get "a pointer to an overloaded function" in any language, because overloading implies multiple bodies). Note that this can't be done by the preprocessor alone, it requires type dispatch of some kind; the preprocessor just changes how it looks. – Alex Celeste Feb 05 '15 at 20:16
  • 5
    As somebody who is fairly familiar with C99 and wants to learn how to do this, this seems overly complicated, even for C. – Tyler Crompton May 03 '16 at 20:06
  • Oooh. When you said that it “looks a bit like a `switch` block”, I thought you were implying that it looks like one but is somewhat different to an extent to which one shouldn't think of it like that (even though you explained it in the next sentence), so that confused me for a minute. It basically *is* a `switch` statement that is evaluated at runtime. It makes sense now. Thanks! – Tyler Crompton May 03 '16 at 21:09
  • 7
    @TylerCrompton It's evaluated at compile time. – JAB Apr 21 '17 at 14:45
  • GCC refuses to compile on empty `__VA_ARGS__`... I could get it working with `(SECOND(0, ##__VA_ARGS__, 0)` instead of `FIRST` and `(_1, ## __VA_ARGS__)` for arguments of function call The mentioned `default` solution works fine, though. How would you solve an additional overload `foo_float(float)`??? – Aconcagua Sep 14 '17 at 09:48
  • Excellent answer with reference to standard and compiler version! – David Bern Aug 07 '20 at 08:25
  • I wouldn't exactly call this dead easy, but I'm as a C++ I avoid macros like the plague. – AustinWBryan Jan 21 '23 at 01:50
  • 1
    I've found a way to make even better use of _Generic(). I used the fact, that function pointers can be defined more than once, and still be the same. With that I can combine any argument list into a type. See my answer. – Cosinus May 13 '23 at 02:12
141

There are a few possibilities:

  1. printf style functions (type as an argument);
  2. OpenGL style functions (type in function name);
  3. C subset of C++ (if You can use a C++ compiler).
Mehdi Charife
  • 722
  • 1
  • 7
  • 22
Jacek Ławrynowicz
  • 2,670
  • 2
  • 23
  • 23
  • 1
    can you explain or provide links for opengl style functions ? – FL4SOF Jan 26 '09 at 12:00
  • 1
    @Lazer: [Here's one](http://cboard.cprogramming.com/c-programming/47291-printf-like-function.html) simple printf-like function implementation. – Alexey Frunze Oct 20 '11 at 10:34
  • 21
    No. printf is not function overloading. it uses vararg !!! And C doesn't support Function Overloading. – hqt Jul 29 '12 at 09:49
  • 76
    @hqt The answer doesn't ever mention the word overloading. – remmy Jun 20 '13 at 16:12
  • How glibc does it? Check `man 2 open`, both `open()` and `openat()` has two signatures, with or without `mode` argument. – dotslashlu Sep 29 '16 at 15:19
  • 3
    @kyrias If the answer isn't about overloading it's on the wrong question – Michael Mrozek May 11 '18 at 21:54
  • @dotslashlu If you read the manual for `open()` carefully, you will realise that whether the `mode` argument is used can be determined from the values of the earlier arguments. `mode` is never set to `0` or some other default - it is unused. Due to the C calling convention, calling a function with less parameters results in the missing parameters being garbage, but the provided parameters are left untouched. Hence, `open()` and `openat()` can simply be defined as a normal function with all parameters present, without using overloading. – Bernard Aug 19 '18 at 06:42
  • 1
    1) Variable arguments is different than overloading. 2) in this case, you have very similarly named function but not equal so they’re not overloaded functions. I believe that you are confused because this is similar to what the c++ compiler does to allow overloading. The difference that with c++ the right function is automatically chosen at compile time. 3) c is not a subset of c++; just try to link your functions compiled by the c++ compiler with your c program and you’ll start to see the reality. If you go and compile everything with the c++ compiler, then you’re into c++ and not into c. – Krauss Aug 11 '20 at 08:21
88

As already stated, overloading in the sense that you mean isn't supported by C. A common idiom to solve the problem is making the function accept a tagged union. This is implemented by a struct parameter, where the struct itself consists of some sort of type indicator, such as an enum, and a union of the different types of values. Example:

#include <stdio.h>

typedef enum {
    T_INT,
    T_FLOAT,
    T_CHAR,
} my_type;

typedef struct {
    my_type type;
    union {
        int a; 
        float b; 
        char c;
    } my_union;
} my_struct;

void set_overload (my_struct *whatever) 
{
    switch (whatever->type) 
    {
        case T_INT:
            whatever->my_union.a = 1;
            break;
        case T_FLOAT:
            whatever->my_union.b = 2.0;
            break;
        case T_CHAR:
            whatever->my_union.c = '3';
    }
}

void printf_overload (my_struct *whatever) {
    switch (whatever->type) 
    {
        case T_INT:
            printf("%d\n", whatever->my_union.a);
            break;
        case T_FLOAT:
            printf("%f\n", whatever->my_union.b);
            break;
        case T_CHAR:
            printf("%c\n", whatever->my_union.c);
            break;
    }

}

int main (int argc, char* argv[])
{
    my_struct s;

    s.type=T_INT;
    set_overload(&s);
    printf_overload(&s);

    s.type=T_FLOAT;
    set_overload(&s);
    printf_overload(&s);

    s.type=T_CHAR;
    set_overload(&s);
    printf_overload(&s); 
}
Nils von Barth
  • 3,239
  • 2
  • 26
  • 27
a2800276
  • 3,272
  • 22
  • 33
  • 24
    Why wouldn't you just make all the `whatever`s into separate functions (`set_int`, `set_float`, etc). Then "tagging with the type" becomes "add the type name to the function name". The version in this answer involves more typing, more runtime cost, more chance of errors that won't be caught at compile time... I fail to see *any advantage at all* to doing things this way! 16 upvotes?! – Ben Jan 29 '13 at 21:24
  • 32
    Ben, this answer is upvoted because it *answers the question,* instead of just saying “don’t do that”. You are correct that it is more idiomatic in C to use separate functions, but if one wants polymorphism in C, this is a good way to do it. Further, this answer shows how you would implement run-time polymorphism in a compiler or VM: tag the value with a type, and then dispatch based on that. It is thus an excellent answer to the original question. – Nils von Barth Nov 08 '14 at 23:12
  • @NilsvonBarth But the question is about overloading, **not** polymorphism, and using the latter to emulate the former is poor advice. – Dmitry Grigoryev Jul 21 '22 at 08:32
  • Great answer, but unfortunately it doesn't cover the case where the function to emulate needs to accept more than one argument, as `union` only allocate space for its largest member. I can see that you can work around this by defining a `struct` to store the variables in question but I'm unsure if this could create some potential problems. – Mehdi Charife Jul 01 '23 at 21:58
35

Here is the clearest and most concise example I've found demonstrating function overloading in C:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int addi(int a, int b) {
    return a + b;
}

char *adds(char *a, char *b) {
    char *res = malloc(strlen(a) + strlen(b) + 1);
    strcpy(res, a);
    strcat(res, b);
    return res;
}

#define add(a, b) _Generic(a, int: addi, char*: adds)(a, b)

int main(void) {
    int a = 1, b = 2;
    printf("%d\n", add(a, b)); // 3

    char *c = "hello ", *d = "world";
    printf("%s\n", add(c, d)); // hello world

    return 0;
}

https://gist.github.com/barosl/e0af4a92b2b8cabd05a7

Jay Taylor
  • 13,185
  • 11
  • 60
  • 85
  • 3
    I think this is a dupe of http://stackoverflow.com/a/25026358/1240268 in spirit (but with less explanation). – Andy Hayden Jul 27 '15 at 05:29
  • 3
    I definitely prefer 1 single continuous block of complete and runnable code to the slicing and dicing chop that is #1240268. To each their own. – Jay Taylor Jul 27 '15 at 17:02
  • 2
    I prefer answers that explain what they're doing and why they work. This does neither. "Best I've seen yet:" is not exposition. – underscore_d Aug 20 '17 at 10:26
  • 1
    This example has a memory leak, check comments on the provided gist: "You create a memory leak by not storing a pointer to the concatenated string before printing it, since now you can't free it after you ```malloc```'d it." – gresolio Oct 11 '21 at 13:37
19

If your compiler is gcc and you don't mind doing hand updates every time you add a new overload you can do some macro magic and get the result you want in terms of callers, it's not as nice to write... but it's possible

look at __builtin_types_compatible_p, then use it to define a macro that does something like

#define foo(a) \
((__builtin_types_compatible_p(int, a)?foo(a):(__builtin_types_compatible_p(float, a)?foo(a):)

but yea nasty, just don't

EDIT: C1X will be getting support for type generic expressions they look like this:

#define cbrt(X) _Generic((X), long double: cbrtl, \
                              default: cbrt, \
                              float: cbrtf)(X)
Spudd86
  • 2,986
  • 22
  • 20
14

This may not help at all, but if you're using clang you can use the overloadable attribute - This works even when compiling as C

http://clang.llvm.org/docs/AttributeReference.html#overloadable

Header

extern void DecodeImageNow(CGImageRef image, CGContextRef usingContext) __attribute__((overloadable));
extern void DecodeImageNow(CGImageRef image) __attribute__((overloadable));

Implementation

void __attribute__((overloadable)) DecodeImageNow(CGImageRef image, CGContextRef usingContext { ... }
void __attribute__((overloadable)) DecodeImageNow(CGImageRef image) { ... }
weakish
  • 28,682
  • 5
  • 48
  • 60
Steazy
  • 383
  • 3
  • 12
  • Wow. I tried to use _Generic as described in other comments, and now I think it's so complicated that it's not practical - it's easier to just abandon the whole idea of overloading functions. This solution is much easier and it's a good argument for clang. Thank you. – makingthematrix Aug 15 '20 at 14:06
13

Yes, sort of.

Here you go by example :

void printA(int a){
printf("Hello world from printA : %d\n",a);
}

void printB(const char *buff){
printf("Hello world from printB : %s\n",buff);
}

#define Max_ITEMS() 6, 5, 4, 3, 2, 1, 0 
#define __VA_ARG_N(_1, _2, _3, _4, _5, _6, N, ...) N
#define _Num_ARGS_(...) __VA_ARG_N(__VA_ARGS__) 
#define NUM_ARGS(...) (_Num_ARGS_(_0, ## __VA_ARGS__, Max_ITEMS()) - 1) 
#define CHECK_ARGS_MAX_LIMIT(t) if(NUM_ARGS(args)>t)
#define CHECK_ARGS_MIN_LIMIT(t) if(NUM_ARGS(args) 
#define print(x , args ...) \
CHECK_ARGS_MIN_LIMIT(1) printf("error");fflush(stdout); \
CHECK_ARGS_MAX_LIMIT(4) printf("error");fflush(stdout); \
({ \
if (__builtin_types_compatible_p (typeof (x), int)) \
printA(x, ##args); \
else \
printB (x,##args); \
})

int main(int argc, char** argv) {
    int a=0;
    print(a);
    print("hello");
    return (EXIT_SUCCESS);
}

It will output 0 and hello .. from printA and printB.

nbanic
  • 1,270
  • 1
  • 8
  • 11
Captain Barbossa
  • 1,067
  • 10
  • 16
13

The following approach is similar to a2800276's, but with some C99 macro magic added:

// we need `size_t`
#include <stddef.h>

// argument types to accept
enum sum_arg_types { SUM_LONG, SUM_ULONG, SUM_DOUBLE };

// a structure to hold an argument
struct sum_arg
{
    enum sum_arg_types type;
    union
    {
        long as_long;
        unsigned long as_ulong;
        double as_double;
    } value;
};

// determine an array's size
#define count(ARRAY) ((sizeof (ARRAY))/(sizeof *(ARRAY)))

// this is how our function will be called
#define sum(...) _sum(count(sum_args(__VA_ARGS__)), sum_args(__VA_ARGS__))

// create an array of `struct sum_arg`
#define sum_args(...) ((struct sum_arg []){ __VA_ARGS__ })

// create initializers for the arguments
#define sum_long(VALUE) { SUM_LONG, { .as_long = (VALUE) } }
#define sum_ulong(VALUE) { SUM_ULONG, { .as_ulong = (VALUE) } }
#define sum_double(VALUE) { SUM_DOUBLE, { .as_double = (VALUE) } }

// our polymorphic function
long double _sum(size_t count, struct sum_arg * args)
{
    long double value = 0;

    for(size_t i = 0; i < count; ++i)
    {
        switch(args[i].type)
        {
            case SUM_LONG:
            value += args[i].value.as_long;
            break;

            case SUM_ULONG:
            value += args[i].value.as_ulong;
            break;

            case SUM_DOUBLE:
            value += args[i].value.as_double;
            break;
        }
    }

    return value;
}

// let's see if it works

#include <stdio.h>

int main()
{
    unsigned long foo = -1;
    long double value = sum(sum_long(42), sum_ulong(foo), sum_double(1e10));
    printf("%Le\n", value);
    return 0;
}
Christoph
  • 164,997
  • 36
  • 182
  • 240
12

In the sense you mean — no, you cannot.

You can declare a va_arg function like

void my_func(char* format, ...);

, but you'll need to pass some kind of information about number of variables and their types in the first argument — like printf() does.

Quassnoi
  • 413,100
  • 91
  • 616
  • 614
6

Leushenko's answer is really cool - solely: the foo example does not compile with GCC, which fails at foo(7), stumbling over the FIRST macro and the actual function call ((_1, __VA_ARGS__), remaining with a surplus comma. Additionally, we are in trouble if we want to provide additional overloads, such as foo(double).

So I decided to elaborate the answer a little further, including to allow a void overload (foo(void) – which caused quite some trouble...).

Idea now is: Define more than one generic in different macros and let select the correct one according to the number of arguments!

Number of arguments is quite easy, based on this answer:

#define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__)

#define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__)
#define CONCAT(X, Y) CONCAT_(X, Y)
#define CONCAT_(X, Y) X ## Y

That's nice, we resolve to either SELECT_1 or SELECT_2 (or more arguments, if you want/need them), so we simply need appropriate defines:

#define SELECT_0() foo_void
#define SELECT_1(_1) _Generic ((_1),    \
        int: foo_int,                   \
        char: foo_char,                 \
        double: foo_double              \
)
#define SELECT_2(_1, _2) _Generic((_1), \
        double: _Generic((_2),          \
                int: foo_double_int     \
        )                               \
)

OK, I added the void overload already – however, this one actually is not covered by the C standard, which does not allow empty variadic arguments, i. e. we then rely on compiler extensions!

At very first, an empty macro call (foo()) still produces a token, but an empty one. So the counting macro actually returns 1 instead of 0 even on empty macro call. We can "easily" eliminate this problem, if we place the comma after __VA_ARGS__ conditionally, depending on the list being empty or not:

#define NARG(...) ARG4_(__VA_ARGS__ COMMA(__VA_ARGS__) 4, 3, 2, 1, 0)

That looked easy, but the COMMA macro is quite a heavy one; fortunately, the topic is already covered in a blog of Jens Gustedt (thanks, Jens). Basic trick is that function macros are not expanded if not followed by parentheses, for further explanations, have a look at Jens' blog... We just have to modify the macros a little to our needs (I'm going to use shorter names and less arguments for brevity).

#define ARGN(...) ARGN_(__VA_ARGS__)
#define ARGN_(_0, _1, _2, _3, N, ...) N
#define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 1, 0)

#define SET_COMMA(...) ,

#define COMMA(...) SELECT_COMMA             \
(                                           \
        HAS_COMMA(__VA_ARGS__),             \
        HAS_COMMA(__VA_ARGS__ ()),          \
        HAS_COMMA(SET_COMMA __VA_ARGS__),   \
        HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \
)

#define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3)
#define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 ## _1 ## _2 ## _3

#define COMMA_0000 ,
#define COMMA_0001
#define COMMA_0010 ,
// ... (all others with comma)
#define COMMA_1111 ,

And now we are fine...

The complete code in one block:

/*
 * demo.c
 *
 *  Created on: 2017-09-14
 *      Author: sboehler
 */

#include <stdio.h>

void foo_void(void)
{
    puts("void");
}
void foo_int(int c)
{
    printf("int: %d\n", c);
}
void foo_char(char c)
{
    printf("char: %c\n", c);
}
void foo_double(double c)
{
    printf("double: %.2f\n", c);
}
void foo_double_int(double c, int d)
{
    printf("double: %.2f, int: %d\n", c, d);
}

#define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__)

#define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__)
#define CONCAT(X, Y) CONCAT_(X, Y)
#define CONCAT_(X, Y) X ## Y

#define SELECT_0() foo_void
#define SELECT_1(_1) _Generic ((_1), \
        int: foo_int,                \
        char: foo_char,              \
        double: foo_double           \
)
#define SELECT_2(_1, _2) _Generic((_1), \
        double: _Generic((_2),          \
                int: foo_double_int     \
        )                               \
)

#define ARGN(...) ARGN_(__VA_ARGS__)
#define ARGN_(_0, _1, _2, N, ...) N

#define NARG(...) ARGN(__VA_ARGS__ COMMA(__VA_ARGS__) 3, 2, 1, 0)
#define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 0)

#define SET_COMMA(...) ,

#define COMMA(...) SELECT_COMMA             \
(                                           \
        HAS_COMMA(__VA_ARGS__),             \
        HAS_COMMA(__VA_ARGS__ ()),          \
        HAS_COMMA(SET_COMMA __VA_ARGS__),   \
        HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \
)

#define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3)
#define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 ## _1 ## _2 ## _3

#define COMMA_0000 ,
#define COMMA_0001
#define COMMA_0010 ,
#define COMMA_0011 ,
#define COMMA_0100 ,
#define COMMA_0101 ,
#define COMMA_0110 ,
#define COMMA_0111 ,
#define COMMA_1000 ,
#define COMMA_1001 ,
#define COMMA_1010 ,
#define COMMA_1011 ,
#define COMMA_1100 ,
#define COMMA_1101 ,
#define COMMA_1110 ,
#define COMMA_1111 ,

int main(int argc, char** argv)
{
    foo();
    foo(7);
    foo(10.12);
    foo(12.10, 7);
    foo((char)'s');

    return 0;
}
Aconcagua
  • 24,880
  • 4
  • 34
  • 59
6

Normally a wart to indicate the type is appended or prepended to the name. You can get away with macros is some instances, but it rather depends what you're trying to do. There's no polymorphism in C, only coercion.

Simple generic operations can be done with macros:

#define max(x,y) ((x)>(y)?(x):(y))

If your compiler supports typeof, more complicated operations can be put in the macro. You can then have the symbol foo(x) to support the same operation different types, but you can't vary the behaviour between different overloads. If you want actual functions rather than macros, you might be able to paste the type to the name and use a second pasting to access it (I haven't tried).

Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
3

I think, I've just found a very elegant solution.

You could (ab)use function pointers to combine types.

_Generic(((void (*)(typeof(1.4) , typeof(9.9) , typeof(4) ))0),
  void (*)(int, double) : printf("int double\n"),
  void (*)(double, double) : printf("double double\n"),
  void (*)(double, double, int) : printf("double double int\n")
  );

With a little bit of macro magic ...

#define PARENS ()

#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
#define EXPAND1(...) __VA_ARGS__

#define FOR_EACH(macro, ...)                                    \
  __VA_OPT__(EXPAND(FOR_EACH_HELPER(macro, __VA_ARGS__)))

#define FOR_EACH_HELPER(macro, a1, ...)                         \
  macro(a1)                                                     \
  __VA_OPT__(, FOR_EACH_AGAIN PARENS (macro, __VA_ARGS__))

#define FOR_EACH_AGAIN() FOR_EACH_HELPER




#define mGROUP_TYPE(...)      void (*)(__VA_ARGS__)
#define mGROUP_TYPE_INST(...) ((void (*)(FOR_EACH(typeof, __VA_ARGS__)))0)

... you can do very beautiful things:

#define myfoo(...) \
  _Generic(mGROUP_TYPE_INST(__VA_ARGS__), \
      mGROUP_TYPE(int, double) : printf("int double\n"), \
      mGROUP_TYPE(double, double) : printf("double double\n"), \
      mGROUP_TYPE(double, double, int) : printf("double double int\n"), \
      mGROUP_TYPE(int, double, int) : printf("int double int\n") \
      )

myfoo(1, 0.4);
myfoo(1, 0.4, 4);

In case the return value is always the same you could even go a step further and use actual function pointers:

#define mFUNC_CASE(fn) typeof(&(fn)) : fn

#define mFUNC_GENERIC_INST(ret, ...) (ret (*) (FOR_EACH(typeof, __VA_ARGS__)))0


#define to_string(...) \
  _Generic(mFUNC_GENERIC_INST(char *, __VA_ARGS__), \
      mFUNC_CASE(int_to_string), \
      mFUNC_CASE(float_to_string), \
      mFUNC_CASE(file_to_string), \
      mFUNC_CASE(vec3_to_string) \
      ) (__VA_ARGS__)

The FOR_EACH() macro originated from here (with a small modifications). There are also other variants of this macro around, that do not need the __VA_OPT__. In case your compiler doesn't support that.

Cosinus
  • 534
  • 4
  • 10
  • This is magnificent, and _so_ much better than my longwinded way of trying to work around the lack of `typeof` in C11! (`typeof` is available from C23 onward). In general, you _probably_ want the operands to an overload to have symmetric types so you want to take the `typeof` the promoted type (e.g. `typeof (A1 + A2)`) and use it for all of them, though there are also legitimate use cases for asymmetric types. – Alex Celeste May 15 '23 at 12:18
0

Can't you just use C++ and not use all other C++ features except this one?

If still no just strict C then I would recommend variadic functions instead.

Tim Matthews
  • 5,031
  • 8
  • 38
  • 45
0

An object-oriented way to emulate function overloading in C that doesn't rely on using preprocessor macros consists of creating a struct for each parameter list that you want your function to accept, and making them all "inherit" from the same parent struct. This "parent" struct will have as a member a function pointer representing the function to emulate. Upon the creation of a child struct this member will be initialized to a corresponding function implementation.

For instance, say that you want to emulate the following behaviour:

int add(int n, int m);
int add(double x, int k, double z);

First, you'll start by creating a struct abstracting whatever is that the different parameter lists represent:

struct summable_t {
    int (*add)(struct summable_t *summable);
};

Then, you create a different struct for each parameter list:

struct summable1_t {
   struct summable_t parent;
   int n;
   int m;
}

struct summable2_t {
   struct summable_t parent;
   double x;
   int k;
   double z;
}

After this, you write a concrete implementation of the function for each child struct (I'll only write the first one to showcase the need for casting):

int add1(struct summable_t *summable) {
    int n = ((struct summable1_t *) summable)->n;
    int m = ((struct summable1_t *) summable)->m;
    return n + m;
};

int add2(struct summable_t *summable) {// some instructions};

Then you glue everything together by defining a "constructor" for each struct:

struct summable_t* new_summable1(int n, int m) {
    struct summable1_t* summable1 = malloc(sizeof(struct summable1_t));
    summable1->n = n;
    summable1->m = m;
    summable1->parent.add = add1;
    return (struct summable_t*) summable1;
};

struct summable_t* new_summable2(double x, int k, double z) {
    struct summable2_t* summable1 = malloc(sizeof(struct summable2_t));
    summable2->x = x;
    summable2->k = k;
    summable2->z = z;

    summable2->parent.add = add2;

    return (struct summable_t*) summable2;
};

Finally, you write a function accepting the parent struct and calling the associated callback:

int add(struct summable_t* summable) {
    return summable->add(summable);
}

In userland, you could consume the above as follows:

int main(int argc, char** argv) {
    struct summable_t* summable1 = new_summable1(1, 2);
    struct summable_t* summable2 = new_summable2(0.5, 2, 0.9);

    int res1 = add(summable1);
    int res2 = add(summable2);

    free(summable1);
    free(summable2);

    return 0;
}
Mehdi Charife
  • 722
  • 1
  • 7
  • 22
-3

Try to declare these functions as extern "C++" if your compiler supports this, http://msdn.microsoft.com/en-us/library/s6y4zxec(VS.80).aspx

dmityugov
  • 4,390
  • 23
  • 18
  • 3
    This may change name mangling to give them unique names (probably not), but it won't suddenly give C overload resolution rules. – Ben Voigt Nov 08 '13 at 15:53
-7

I hope the below code will help you to understand function overloading

#include <stdio.h>
#include<stdarg.h>

int fun(int a, ...);
int main(int argc, char *argv[]){
   fun(1,10);
   fun(2,"cquestionbank");
   return 0;
}
int fun(int a, ...){
  va_list vl;
  va_start(vl,a);

  if(a==1)
      printf("%d",va_arg(vl,int));
   else
      printf("\n%s",va_arg(vl,char *));
}
Community
  • 1
  • 1