views:

3270

answers:

10

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, looking for workarounds if any?

+12  A: 

There are 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)
Jacek Ławrynowicz
can you explain or provide links for opengl style functions ?
FL4SOF
take a look at http://www.glprogramming.com/red/chapter01.html#name3
Jacek Ławrynowicz
@Jacek Ławrynowicz: Any good links for "printf style functions"?
Lazer
A: 

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
Not if a C++ compiler is not available for the OS he is coding for.
Brian
Yeah mind if I ask what os
Tim Matthews
A: 

Why not compile it as C++ but use only C constructs?

Georg
You assume a C++ compiler is available for the OS he is coding for.
Brian
Function overloading is a C++ construct.
Pete Kirkham
+3  A: 

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
+2  A: 

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
can you explain a little more on macro based approach.
FL4SOF
+2  A: 

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 struct parameter. The struct itself would consist of some sort of type indicator and a union of the different types of values. Example:

#include <stdio.h>

#define T_INT   1
#define T_FLOAT 2
#define T_CHAR  3


typedef struct {
    int 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);

}
+4  A: 

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
A: 

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
A: 

how about way used in tgmath.h ?

vitaly.v.ch
+1  A: 

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

Spudd86