0

Is it possible to make polymorphic functions with C where we don't have to use any classes or OOP type function calls in the main function?

Like, I want to make a function to return the minimum value among two integers or characters or strings. I just want to call the function like function_name(variable1, variable2) in main function.

It is quite easy to do with C++ templates but is there any way to do it with C? I've gone through closely all "polymorphism with C" related questions and answers but couldn't find any clue.

Fuad
  • 1
  • 2
  • Check out how e.g. `qsort()` does it. That’s what you can do. Apart from that there’s [`_Generic`](https://en.cppreference.com/w/c/language/generic) for type dispatch. – Konrad Rudolph Mar 14 '21 at 11:31
  • 1
    Does this answer your question? [C11 \_Generic usage](https://stackoverflow.com/questions/40096584/c11-generic-usage) – jordanvrtanoski Mar 14 '21 at 12:15
  • @jordanvrtanoski _Generic cannot differentiate char and int array, like for doing getting length of an array and a char array (string), it cannot be used. What to do in this case? – Fuad Mar 20 '21 at 06:20
  • @Fuad, it's not possible to do all the things that a `C++` templates are doing for a simple reason that the templates are evaluated during semantic parsing, while macros are evaluated during preprocessing. – jordanvrtanoski Mar 20 '21 at 08:06
  • @jordanvrtanoski How you would write a function to get the length of an string or an array in c? – Fuad Mar 20 '21 at 08:17
  • Statically allocated arrays are checked during compile-time, during semantic parsing. As for the dynamic arrays, as far as `C` compiler is concerned, they are pointers. A pointer points to a start of a memory location, and that's it, the length is unknown. The end of the location (the length) is determined by the developer by writing code and by using some coding standards. – jordanvrtanoski Mar 20 '21 at 08:41
  • There is a standard for strings (which are pointers to arrays of `char`) that the end is at location that has `\0`, so counting the bytes until `\0` is reached will give you the answer. For other types, there are no standards. Even for `char *` you are not required to follow the standard if you don't use standard functions. You are free to write your own functions that will consider different standards (example `pascal` standard). `C` is low level language and the developer is free to define it's own memory organization. – jordanvrtanoski Mar 20 '21 at 08:42
  • @jordanvrtanoski Thank You, Nice Lead. Can you give me some standard working examples of writing functions that can do things like this? – Fuad Mar 20 '21 at 08:59
  • check this [SO](https://stackoverflow.com/a/45966153/2816703) – jordanvrtanoski Mar 20 '21 at 09:51

1 Answers1

1

Sometimes a #define can do what you want.

But it is hard and complicated to use. Take the max macro in linux for example:

From linux 5.12-rc2:/include/linux/minmax.h

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_MINMAX_H
#define _LINUX_MINMAX_H

/*
 * min()/max()/clamp() macros must accomplish three things:
 *
 * - avoid multiple evaluations of the arguments (so side-effects like
 *   "x++" happen only once) when non-constant.
 * - perform strict type-checking (to generate warnings instead of
 *   nasty runtime surprises). See the "unnecessary" pointer comparison
 *   in __typecheck().
 * - retain result as a constant expressions when called with only
 *   constant expressions (to avoid tripping VLA warnings in stack
 *   allocation usage).
 */
#define __typecheck(x, y) \
    (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))

/*
 * This returns a constant expression while determining if an argument is
 * a constant expression, most importantly without evaluating the argument.
 * Glory to Martin Uecker <Martin.Uecker@med.uni-goettingen.de>
 */
#define __is_constexpr(x) \
    (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))

#define __no_side_effects(x, y) \
        (__is_constexpr(x) && __is_constexpr(y))

#define __safe_cmp(x, y) \
        (__typecheck(x, y) && __no_side_effects(x, y))

#define __cmp(x, y, op) ((x) op (y) ? (x) : (y))

#define __cmp_once(x, y, unique_x, unique_y, op) ({ \
        typeof(x) unique_x = (x);       \
        typeof(y) unique_y = (y);       \
        __cmp(unique_x, unique_y, op); })

#define __careful_cmp(x, y, op) \
    __builtin_choose_expr(__safe_cmp(x, y), \
        __cmp(x, y, op), \
        __cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op))

/**
 * min - return minimum of two values of the same or compatible types
 * @x: first value
 * @y: second value
 */
#define min(x, y)   __careful_cmp(x, y, <)

/**
 * max - return maximum of two values of the same or compatible types
 * @x: first value
 * @y: second value
 */
#define max(x, y)   __careful_cmp(x, y, >)

/**
 * min3 - return minimum of three values
 * @x: first value
 * @y: second value
 * @z: third value
 */
#define min3(x, y, z) min((typeof(x))min(x, y), z)

/**
 * max3 - return maximum of three values
 * @x: first value
 * @y: second value
 * @z: third value
 */
#define max3(x, y, z) max((typeof(x))max(x, y), z)

The C language itself has no appropriate way to handle this.

For lightweight projects, you can simply implement such a function for every type:

int min(int a, int b) {...}
short min(short a, short b) {...}
float min(float a, float b) {...}
...
aleck099
  • 428
  • 2
  • 10
  • How you would write a function to get the length of an string or an array in c? – Fuad Mar 20 '21 at 06:22
  • As everyone knows, C strings are ended with a `'\0'`. Use `strlen()` to get their lengths. Some coders make all arrays end with a `NULL` object (e.g. `{"foo", "bar", "foo", NULL}`). Get their lengths as what `strlen()` does. – aleck099 Mar 22 '21 at 04:26