Function overloading in C

0xog_pg

PGzlan

Posted on July 8, 2023

Function overloading in C

Function overloading is regarded as powerful feature in programming languages. It allows developers to define multiple functions that take different arguments while having the same name.

This can be a convenient method of writing code that is more readable, maintainable, and reusable.

In C, function overloading is not a built-in feature, but it can be achieved through a technique called "name mangling" or "function name decoration" (more on that in an upcoming post).

In this post, we will explore some methods that can help us achieve function overloading in C.

Using _Generic keyword/macro

While function overloading is not supported in C, you can achieve similar functionality by using the _Generic keyword, which is available in C11 and later

#include <stdio.h>

#define double_num(x) _Generic((x), \
    int: double_int, \
    float: double_float, \
    long: double_long \
)(x)

int double_int(int num) {
    return num * 2;
}

float double_float(float num) {
    return num * 2.0;
}

long double_long(long num) {
    return num * 2;
}

int main() {
    int v1 = 2;
    float v2 = 3.0f;
    long v3 = 4;

    int x = double_num(v1);
    printf("%d doubled again is %d\n", v1, x);

    float y = double_num(v2);
    printf("%f doubled again is %f\n", v2, y);

    long z = double_num(v3);
    printf("%ld doubled again is %ld\n", v3, z);   

    return 0;

}
Enter fullscreen mode Exit fullscreen mode

Using clang attribute overloadable:

The Clang compiler, compiler that supports multiple programming languages including OpenMP, OpenCL and other framework, has a feature called attributes which are used to declare additional information about the behavior of functions, variables, types, and other language constructs.

The overloadable attribute can be used to achieve function overloading in C.

#include <stdio.h>

__attribute__((overloadable)) int double_num(int num) {
    return num * 2;
}

__attribute__((overloadable)) float double_num(float num) {
    return num * 2.0;
}

__attribute__((overloadable)) long double_num(long num) {
    return num * 2;
}


int main() {
    int v1 = 2;
    float v2 = 3.0f;
    long v3 = 4;

    int x = double_num(v1);
    printf("%d doubled again is %d\n", v1, x);

    float y = double_num(v2);
    printf("%f doubled again is %f\n", v2, y);

    long z = double_num(v3);
    printf("%ld doubled again is %ld\n", v3, z);

    return 0;

}
Enter fullscreen mode Exit fullscreen mode

The overloadable attribute is a Clang-specific extension, so it is not portable to other compilers. This means that if you use this attribute, your code may not compile with other compilers such as GCC or MSVC. There are also some caveats that come with using attributes. If you're interested in knowing more about how they work, be sure to check the link in the references section.

Using varargs

In C, varargs refers to a feature that allows functions to accept a variable number of arguments. This is achieved through the use of the stdarg.h header file, which defines a set of macros for accessing the arguments passed to a function.

A function that uses varargs must include an ellipsis (...) as the last parameter in its parameter list. This indicates that the function can accept additional arguments after the named parameters. The va_list, va_start, va_arg, and va_end macros are then used within the function to access these additional arguments.

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


int double_num(const char* format, ...) {
    va_list args;
    va_start(args, format);
    if (strcmp(format, "%d") == 0) {
        int num = va_arg(args, int);
        va_end(args);
        return num * 2;
    } else if (strcmp(format, "%f") == 0) {
        float num = va_arg(args, double);
        va_end(args);
        return num * 2.0;
    } else if (strcmp(format, "%ld") == 0) {
        long num = va_arg(args, long);
        va_end(args);
        return num * 2;
    }
    va_end(args);
    return 0;
}

int main() {

    int v1 = 2;
    float v2 = 3.0f;
    long v3 = 4;

    int x = double_num("%d", v1);
    printf("%d doubled again is %d\n", v1, x);

    float y = double_num("%f", v2);
    printf("%.2f doubled again is %.2f\n", v2, y);

    long z = double_num("%ld", v3);
    printf("%ld doubled again is %ld\n", v3, z);

    return 0;

}
Enter fullscreen mode Exit fullscreen mode

In a following post, we'll explore more on what this actually translates to in terms of the compile file that runs this code.

Note: All the previous code, apart from the clang one, were built with gcc. The clang one can be built using the same style as gcc. You just have to replace gcc with clang in your command

References

https://clang.llvm.org/docs/AttributeReference.html
https://www.udacity.com/blog/2021/09/cp-function-overloading-what-you-need-to-know.html
https://learn.microsoft.com/en-us/cpp/cpp/function-overloading?view=msvc-170
https://stackoverflow.com/questions/36504216/function-overloading-in-c-without-using-generic
https://stackoverflow.com/questions/64408323/how-to-overload-functions-in-c
Attributes in Clang — Clang 17.0.0git documentation (llvm.org)

💖 💪 🙅 🚩
0xog_pg
PGzlan

Posted on July 8, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related