Is it possible to write a universal function in C? For example, a function that can add numbers of type int, float, double, etc., or a function that searches for the maximum element in an array of arbitrary type. If so, can you give an example.
1 answer
A function that directly works with different (incompatible) types of arguments in such fairly strongly typed languages as C or C ++ is generally impossible to write. For a more or less elegant solution of such problems, C ++ provides mechanisms such as runtime polymorphism, function overloading and / or function templates. In the last two options, you get not a function, but a set of functions, either explicitly defined by you or implicitly generated for you by the compiler.
In the language With such mechanisms at the kernel level there is no language (or they are not available to the user). However, in C, you can emulate them with varying degrees of similarity or convenience.
The universal function of searching for the maximum element of an array can be implemented in C based on runtime polymorphism via a callback comparator, just as is done in standard
qsortorbsearch#include <stdio.h> int cmp_int(const void *l, const void *r) { int li = *(const int *) l, ri = *(const int *) r; return (li > ri) - (li < ri); } int cmp_double(const void *l, const void *r) { double li = *(const double *) l, ri = *(const double *) r; return (li > ri) - (li < ri); } void *max_element(const void *a, size_t n, size_t size, int cmp(const void *, const void *)) { const void *max = a; if (n > 0) while (--n > 0) { a = (const char *) a + size; if (cmp(max, a) < 0) max = a; } return (void *) max; } int main() { const int a[] = { 1, 2, 8, 7, 3, 2, 5 }; const int *max_i = max_element(a, sizeof a / sizeof *a, sizeof *a, cmp_int); printf("%d\n", *max_i); const double b[] = { 1., 2., 8., 7., 3., 2., 5. }; const double *max_d = max_element(b, sizeof b / sizeof *b, sizeof *b, cmp_double); printf("%lf\n", *max_d); }Overloading mechanisms or templates can be emulated through macros, either directly implementing the required macro functionality, or using macros to instantiate the required versions of functions (with different names, of course)
#define COMPARE(l, r) (((l) > (r)) - ((l) < (r))) #define DEFINE_COMPARATOR(T, suffix)\ int cmp_##suffix(const void *l, const void *r)\ {\ const T *lhs = l, *rhs = r;\ return COMPARE(*lhs, *rhs); } ... DEFINE_COMPARATOR(int, int) DEFINE_COMPARATOR(double, double)Using the
_Genericfunctionality (either alone or together with clause 2) in many cases in C you can implement a fairly accurate similarity to overloading functions from C ++, i.e. to reduce several different functions under one "dispatcher" of calls.#include <stdio.h> #define DEFINE_ADD(T, suffix) T add_##suffix(T lhs, T rhs) { return lhs + rhs; } DEFINE_ADD(int, int) DEFINE_ADD(double, double) #define add(lhs, rhs) _Generic((lhs) + (rhs),\ int : add_int,\ double : add_double)((lhs), (rhs)) int main() { int a = 1, b = 5; double c = 4.0, d = 8.5; printf("%d %lf\n", add(a, b), add(c, d)); }
_Generic). - Harry