3

Maybe its just a dumb question but I was wondering if there is a way to allow two data types in the same function parameter, sort of polimorphism that in the end does the same stuff, just to filter out some garbage input.

typedef enum
{

} type1_t;

typedef enum
{

} type2_t;

void myfunc(typex_t foo)
{

}
sorh
  • 332
  • 3
  • 10
  • 3
    Short answer: No. C is a strongly typed language. Long answer: Sort of with `void*` and lots of voodoo, but that has the opposite effect of "filtering out garbage" as it lets anything in. – tadman Jan 14 '21 at 14:05
  • 3
    You can use a`union` maybe? – Iharob Al Asimi Jan 14 '21 at 14:06
  • 4
    You can't use only one function. You can however use macros and [generic selection](https://en.cppreference.com/w/c/language/generic) to call one of two functions depending on the type. – Some programmer dude Jan 14 '21 at 14:07
  • 1
    I would suggest using a tagged union. – Ivan C Jan 14 '21 at 14:08
  • 2
    If it's just enums, you could use an int. But in any case you'll need a way of knowing what type was passed, won't you? – Dmitri Jan 14 '21 at 14:09
  • 2
    What problem are you trying to solve with this? Maybe this is an [XY Problem](https://xyproblem.info/) (I might be wrong). And what would you do with `foo` in `myfunc`? [Edit] and show expand your example. – Jabberwocky Jan 14 '21 at 14:21
  • Would your purpose be satisfied with either one type or the other, or do both need to be passed (therefore accessible from) the same parameter? i.e. if either/or use a `union`, if both, use a `struct` – ryyker Jan 14 '21 at 14:36
  • Main problem here isn't the enum type actually, but to pass on an _enumeration constant_, since those always have type `int`. You can use some tricks from here: [How to create type safe enums?](https://stackoverflow.com/questions/43043246/how-to-create-type-safe-enums). – Lundin Jan 14 '21 at 14:58

2 Answers2

6

You may consider a different approach, involving one of C11 features.

A generic selection

Provides a way to choose one of several expressions at compile time, based on a type of a controlling expression.

You'll end up with some code duplication, but also a common "interface".

#include <stdio.h>

void myfunc_int(int x){
    printf("int: %d\n", x);
}
void myfunc_float(float y){
    printf("float: %f\n", y);
}

#define myfunc(X) _Generic((X),     \
    int : myfunc_int,               \
    float : myfunc_float            \
) (X)

int main(void)
{
    myfunc(3.14f);

    myfunc(42);

//    myfunc(1.0);
//           ^ "error: '_Generic' selector of type 'double'
//                    is not compatible with any association"
}

Testable here.

Bob__
  • 12,361
  • 3
  • 28
  • 42
  • although it seems to work the code duplication is a big price to pay for such thing – sorh Jan 14 '21 at 16:26
4

Tagged Union

You could use a union:

typedef union
{
    type1_t t1;
    type2_t t2;
} UnionType;

You need to somehow know if t1 or t2 is active. For this you can pass an additional enumeration value (A distinct value for each type you want to allow):

enum types
{
    TYPE1,
    TYPE2
};

Combine it to a struct, and there you have your typex_t:

typedef struct
{
    enum types type; // this is also called a type tag
    UnionType content;
} typex_t;

Or more compact (nonstandard)

typedef struct
{
    enum { TYPE1, TYPE2 } type;
    union { type1_t t1; type2_t t2; } content;
} typex_t;

This whole struct union construct is also called a tagged union.

cmdLP
  • 1,658
  • 9
  • 19
  • In modern C you can do anonymous `union { type1_t t1; type2_t t2; };`. But then in modern C you'd probably use `_Generic` instead of them old enum tricks from back in the days. – Lundin Jan 14 '21 at 14:55