Wie erreicht man eine Funktionsüberladung in C?


240

Gibt es eine Möglichkeit, eine Funktionsüberladung in C zu erreichen? Ich betrachte einfache Funktionen, die überladen werden sollen

foo (int a)  
foo (char b)  
foo (float c , int d)

Ich denke, es gibt keinen direkten Weg; Ich suche nach Problemumgehungen, falls vorhanden.


6
Warum willst du das tun? C hat keine polymorphen Fähigkeiten. Foo (zufälliger Typ) ist also unmöglich. Machen Sie einfach echte Funktionen foo_i, foo_ch, foo_d usw.
jmucchiello

4
Sie können den bösen Weg gehen, indem Sie leere Zeiger verwenden und IDs eingeben.
Alk

11
Ich sollte auf die Tatsache aufmerksam machen, dass sich die Antwort auf diese Frage geändert hat, seit sie ursprünglich mit dem neuen C-Standard gestellt wurde.
Leushenko

Antworten:


127

Es gibt nur wenige Möglichkeiten:

  1. Funktionen im printf-Stil (Typ als Argument)
  2. Funktionen im OpenGL-Stil (Funktionsnamen eingeben)
  3. c-Teilmenge von c ++ (wenn Sie einen c ++ - Compiler verwenden können)

1
Können Sie Links für Funktionen im OpenGL-Stil erklären oder bereitstellen?
FL4SOF

1
@Lazer: Hier ist eine einfache Implementierung einer printf-ähnlichen Funktion.
Alexey Frunze

12
Nein. Printf ist keine Funktionsüberladung. es benutzt vararg !!! Und C unterstützt keine Funktionsüberladung.
hqt

52
@hqt In der Antwort wird das Wort Überladung nie erwähnt.
Cyrias

1
@kyrias Wenn die Antwort nicht überladen ist, ist es auf der falschen Frage
Michael Mrozek

233

Ja!

In der Zeit seit dieser Frage hat Standard C (keine Erweiterungen) effektiv gewonnen Unterstützung für die Funktion Überlastung (nicht Betreiber), dank der Zugabe des _GenericSchlüsselwort in C11. (wird in GCC seit Version 4.9 unterstützt)

(Überladen ist nicht wirklich "eingebaut" in der in der Frage gezeigten Weise, aber es ist kinderleicht, etwas zu implementieren, das so funktioniert.)

_Genericist ein Operator zur Kompilierungszeit in derselben Familie wie sizeofund _Alignof. Es ist in Standardabschnitt 6.5.1.1 beschrieben. Es werden zwei Hauptparameter akzeptiert: ein Ausdruck (der zur Laufzeit nicht ausgewertet wird) und eine Typ- / Ausdruckszuordnungsliste, die ein bisschen wie ein switchBlock aussieht . _GenericRuft den Gesamttyp des Ausdrucks ab und "schaltet" ihn ein, um den Endergebnisausdruck in der Liste für seinen Typ auszuwählen:

_Generic(1, float: 2.0,
            char *: "2",
            int: 2,
            default: get_two_object());

Der obige Ausdruck 2ergibt - der Typ des steuernden Ausdrucks ist int, also wählt er den Ausdruck, der intals Wert zugeordnet ist. Nichts davon bleibt zur Laufzeit übrig. (Dasdefault Klausel ist optional: Wenn Sie sie weglassen und der Typ nicht übereinstimmt, wird ein Kompilierungsfehler verursacht.)

Dies ist nützlich für das Überladen von Funktionen, da es vom C-Präprozessor eingefügt werden kann und einen Ergebnisausdruck basierend auf dem Typ der an das steuernde Makro übergebenen Argumente auswählt. Also (Beispiel aus dem C-Standard):

#define cbrt(X) _Generic((X),                \
                         long double: cbrtl, \
                         default: cbrt,      \
                         float: cbrtf        \
                         )(X)

Dieses Makro implementiert eine überladene cbrtOperation, indem es den Typ des Arguments an das Makro weiterleitet, eine geeignete Implementierungsfunktion auswählt und dann das ursprüngliche Makroargument an diese Funktion übergibt.

Um Ihr ursprüngliches Beispiel zu implementieren, können wir Folgendes tun:

foo_int (int a)  
foo_char (char b)  
foo_float_int (float c , int d)

#define foo(_1, ...) _Generic((_1),                                  \
                              int: foo_int,                          \
                              char: foo_char,                        \
                              float: _Generic((FIRST(__VA_ARGS__,)), \
                                     int: foo_float_int))(_1, __VA_ARGS__)
#define FIRST(A, ...) A

In diesem Fall hätten wir eine default:Zuordnung für den dritten Fall verwenden können, aber das zeigt nicht, wie das Prinzip auf mehrere Argumente ausgedehnt werden kann. Das Endergebnis ist, dass Sie foo(...)in Ihrem Code verwenden können, ohne sich (viel [1]) über die Art seiner Argumente Gedanken zu machen.


In komplizierteren Situationen, z. B. Funktionen, die eine größere Anzahl von Argumenten überladen oder Zahlen variieren, können Sie Dienstprogrammmakros verwenden, um automatisch statische Versandstrukturen zu generieren:

void print_ii(int a, int b) { printf("int, int\n"); }
void print_di(double a, int b) { printf("double, int\n"); }
void print_iii(int a, int b, int c) { printf("int, int, int\n"); }
void print_default(void) { printf("unknown arguments\n"); }

#define print(...) OVERLOAD(print, (__VA_ARGS__), \
    (print_ii, (int, int)), \
    (print_di, (double, int)), \
    (print_iii, (int, int, int)) \
)

#define OVERLOAD_ARG_TYPES (int, double)
#define OVERLOAD_FUNCTIONS (print)
#include "activate-overloads.h"

int main(void) {
    print(44, 47);   // prints "int, int"
    print(4.4, 47);  // prints "double, int"
    print(1, 2, 3);  // prints "int, int, int"
    print("");       // prints "unknown arguments"
}

( Umsetzung hier ) Mit etwas Aufwand können Sie die Anzahl der Boilerplates so reduzieren, dass sie einer Sprache mit nativer Unterstützung für Überladung ähneln.

Abgesehen davon war es bereits möglich , die Anzahl der Argumente (nicht den Typ) in C99 zu überladen .


[1] Beachten Sie, dass die Art und Weise, wie C Typen bewertet, Sie jedoch möglicherweise stolpern lässt. Dies wählt aus, foo_intwenn Sie beispielsweise versuchen, ein Zeichenliteral zu übergeben, und Sie müssen ein wenig herumspielen, wenn Ihre Überladungen Zeichenfolgenliterale unterstützen sollen. Trotzdem insgesamt ziemlich cool.


Anhand Ihres Beispiels sieht es so aus, als ob nur Funktionen wie Makros überladen werden. Lassen Sie mich sehen, ob ich richtig verstehe: Wenn Sie Funktionen überladen möchten, verwenden Sie nur den Präprozessor, um den Funktionsaufruf basierend auf den übergebenen Datentypen umzuleiten, oder?
Nick

Leider gehe ich davon aus, dass MISRA diese Funktion aus den gleichen Gründen, aus denen sie Listen mit variablen Argumenten verbietet, nicht akzeptiert, wenn C11 anfängt, sich durchzusetzen. Ich versuche, mich in meiner Welt ziemlich nah an MISRA zu halten.
Nick

9
@ Nick das ist alles Überladung ist. Es wird nur implizit in anderen Sprachen behandelt (z. B. kann man in keiner Sprache wirklich "einen Zeiger auf eine überladene Funktion" erhalten, da Überladen mehrere Körper impliziert). Beachten Sie, dass dies nicht allein vom Präprozessor durchgeführt werden kann, sondern dass ein Typversand erforderlich ist. Der Präprozessor ändert nur das Aussehen.
Leushenko

1
Als jemand, der mit C99 ziemlich vertraut ist und lernen möchte, wie man das macht, scheint dies selbst für C.
Tyler Crompton

5
@ TylerCrompton Wird beim Kompilieren ausgewertet.
JAB

75

Wie bereits erwähnt, wird Überladung in dem Sinne, wie Sie meinen, von C nicht unterstützt. Eine gängige Redewendung zur Lösung des Problems besteht darin, dass die Funktion eine markierte Vereinigung akzeptiert . Dies wird durch einen structParameter implementiert , bei dem der structselbst aus einer Art Typindikator besteht, z. B. einem enumund einem unionder verschiedenen Wertetypen. Beispiel:

#include <stdio.h>

typedef enum {
    T_INT,
    T_FLOAT,
    T_CHAR,
} my_type;

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

22
Warum würden Sie nicht machen einfach alle whatevers in getrennte Funktionen ( set_int, set_floatusw.). Dann wird "Markieren mit dem Typ" zu "Hinzufügen des Typnamens zum Funktionsnamen". Die Version in dieser Antwort beinhaltet mehr Eingabe, mehr Laufzeitkosten, mehr Wahrscheinlichkeit von Fehlern, die beim Kompilieren nicht abgefangen werden ... Ich sehe überhaupt keinen Vorteil darin, Dinge auf diese Weise zu tun! 16 positive Stimmen?!
Ben

20
Ben, diese Antwort wird positiv bewertet, weil sie die Frage beantwortet, anstatt nur zu sagen: " Tu das nicht". Sie haben Recht, dass es in C idiomatischer ist, separate Funktionen zu verwenden, aber wenn man in C Polymorphismus will, ist dies ein guter Weg, dies zu tun. Darüber hinaus zeigt diese Antwort, wie Sie einen Laufzeitpolymorphismus in einem Compiler oder einer VM implementieren würden: Kennzeichnen Sie den Wert mit einem Typ und versenden Sie ihn basierend darauf. Es ist somit eine hervorragende Antwort auf die ursprüngliche Frage.
Nils von Barth

20

Hier ist das klarste und prägnanteste Beispiel, das ich gefunden habe, um das Überladen von Funktionen in C zu demonstrieren:

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

int addi(int a, int b) {
    return a + b;
}

char *adds(char *a, char *b) {
    char *res = malloc(strlen(a) + strlen(b) + 1);
    strcpy(res, a);
    strcat(res, b);
    return res;
}

#define add(a, b) _Generic(a, int: addi, char*: adds)(a, b)

int main(void) {
    int a = 1, b = 2;
    printf("%d\n", add(a, b)); // 3

    char *c = "hello ", *d = "world";
    printf("%s\n", add(c, d)); // hello world

    return 0;
}

https://gist.github.com/barosl/e0af4a92b2b8cabd05a7


1
Ich denke, dies ist ein Betrug von stackoverflow.com/a/25026358/1240268 im Geiste (aber mit weniger Erklärung).
Andy Hayden

1
Ich bevorzuge definitiv einen einzelnen fortlaufenden Block mit vollständigem und ausführbarem Code gegenüber dem Schneiden und Würfeln mit der Nummer 1240268. Jedem das Seine.
Jay Taylor

1
Ich bevorzuge Antworten, die erklären, was sie tun und warum sie funktionieren. Dies tut beides nicht. "Das Beste, was ich bisher gesehen habe:" ist keine Ausstellung.
underscore_d

19

Wenn Ihr Compiler gcc ist und es Ihnen nichts ausmacht, jedes Mal Hand-Updates durchzuführen, wenn Sie eine neue Überladung hinzufügen, können Sie Makromagie anwenden und das gewünschte Ergebnis in Bezug auf Anrufer erzielen. Es ist nicht so schön zu schreiben ... aber es ist möglich

Schauen Sie sich __builtin_types_compatible_p an und definieren Sie damit ein Makro, das so etwas tut

#define foo(a) \
((__builtin_types_compatible_p(int, a)?foo(a):(__builtin_types_compatible_p(float, a)?foo(a):)

aber ja böse, einfach nicht

BEARBEITEN : C1X wird Unterstützung für generische Typausdrücke erhalten, die so aussehen:

#define cbrt(X) _Generic((X), long double: cbrtl, \
                              default: cbrt, \
                              float: cbrtf)(X)

13

Mehr oder weniger.

Hier gehen Sie mit gutem Beispiel voran:

void printA(int a){
printf("Hello world from printA : %d\n",a);
}

void printB(const char *buff){
printf("Hello world from printB : %s\n",buff);
}

#define Max_ITEMS() 6, 5, 4, 3, 2, 1, 0 
#define __VA_ARG_N(_1, _2, _3, _4, _5, _6, N, ...) N
#define _Num_ARGS_(...) __VA_ARG_N(__VA_ARGS__) 
#define NUM_ARGS(...) (_Num_ARGS_(_0, ## __VA_ARGS__, Max_ITEMS()) - 1) 
#define CHECK_ARGS_MAX_LIMIT(t) if(NUM_ARGS(args)>t)
#define CHECK_ARGS_MIN_LIMIT(t) if(NUM_ARGS(args) 
#define print(x , args ...) \
CHECK_ARGS_MIN_LIMIT(1) printf("error");fflush(stdout); \
CHECK_ARGS_MAX_LIMIT(4) printf("error");fflush(stdout); \
({ \
if (__builtin_types_compatible_p (typeof (x), int)) \
printA(x, ##args); \
else \
printB (x,##args); \
})

int main(int argc, char** argv) {
    int a=0;
    print(a);
    print("hello");
    return (EXIT_SUCCESS);
}

Es wird 0 und hallo .. von printA und printB ausgegeben.


2
int main (int argc, char ** argv) {int a = 0; Druck (a); print ("Hallo"); return (EXIT_SUCCESS); } gibt 0 und hallo aus .. von printA und printB ...
Captain Barbossa

1
__builtin_types_compatible_p, ist das nicht GCC-Compiler-spezifisch?
Sogartar

11

Der folgende Ansatz ähnelt dem von a2800276 , jedoch mit etwas C99- Makromagie :

// 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;
}

11

Dies hilft möglicherweise überhaupt nicht, aber wenn Sie clang verwenden, können Sie das überladbare Attribut verwenden. Dies funktioniert auch beim Kompilieren als C.

http://clang.llvm.org/docs/AttributeReference.html#overloadable

Header

extern void DecodeImageNow(CGImageRef image, CGContextRef usingContext) __attribute__((overloadable));
extern void DecodeImageNow(CGImageRef image) __attribute__((overloadable));

Implementierung

void __attribute__((overloadable)) DecodeImageNow(CGImageRef image, CGContextRef usingContext { ... }
void __attribute__((overloadable)) DecodeImageNow(CGImageRef image) { ... }

10

In dem Sinne, wie du meinst - nein, das kannst du nicht.

Sie können eine va_argFunktion wie deklarieren

void my_func(char* format, ...);

Sie müssen jedoch im ersten Argument Informationen über die Anzahl der Variablen und ihre Typen übergeben - wie dies auch der printf()Fall ist.


6

Normalerweise wird eine Warze zur Angabe des Typs an den Namen angehängt oder vorangestellt. Sie können in einigen Fällen mit Makros davonkommen, aber es hängt eher davon ab, was Sie versuchen zu tun. Es gibt keinen Polymorphismus in C, nur Zwang.

Einfache generische Operationen können mit Makros ausgeführt werden:

#define max(x,y) ((x)>(y)?(x):(y))

Wenn Ihr Compiler typeof unterstützt , können kompliziertere Operationen in das Makro eingefügt werden. Sie können dann das Symbol foo (x) verwenden, um dieselbe Operation für verschiedene Typen zu unterstützen, aber Sie können das Verhalten zwischen verschiedenen Überladungen nicht variieren. Wenn Sie tatsächliche Funktionen anstelle von Makros möchten, können Sie den Typ möglicherweise in den Namen einfügen und mit einem zweiten Einfügen darauf zugreifen (ich habe es nicht versucht).


Können Sie etwas mehr über den makrobasierten Ansatz erklären?
FL4SOF

4

Leushenkos Antwort ist wirklich cool - nur: Das fooBeispiel wird nicht mit GCC kompiliert, das bei fehlschlägt foo(7)und über das FIRSTMakro und den tatsächlichen Funktionsaufruf stolpert ( (_1, __VA_ARGS__)wobei ein Überschusskomma verbleibt. Außerdem sind wir in Schwierigkeiten, wenn wir zusätzliche Überladungen bereitstellen möchten , wie z foo(double).

Deshalb habe ich mich entschlossen, die Antwort etwas weiter auszuarbeiten, einschließlich einer Überlastung der Leere ( foo(void)- was einige Probleme verursachte ...).

Die Idee ist jetzt: Definieren Sie mehr als ein Generikum in verschiedenen Makros und lassen Sie das richtige entsprechend der Anzahl der Argumente auswählen!

Die Anzahl der Argumente ist aufgrund dieser Antwort recht einfach :

#define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__)

#define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__)
#define CONCAT(X, Y) CONCAT_(X, Y)
#define CONCAT_(X, Y) X ## Y

Das ist schön, wir lösen entweder SELECT_1oder SELECT_2(oder mehr Argumente, wenn Sie sie wollen / brauchen) auf, also brauchen wir einfach geeignete Definitionen:

#define SELECT_0() foo_void
#define SELECT_1(_1) _Generic ((_1),    \
        int: foo_int,                   \
        char: foo_char,                 \
        double: foo_double              \
)
#define SELECT_2(_1, _2) _Generic((_1), \
        double: _Generic((_2),          \
                int: foo_double_int     \
        )                               \
)

OK, ich habe die Leerenüberladung bereits hinzugefügt - diese wird jedoch nicht vom C-Standard abgedeckt, der keine leeren variadischen Argumente zulässt, dh wir verlassen uns dann auf Compiler-Erweiterungen !

Zunächst erzeugt ein leerer Makroaufruf ( foo()) immer noch ein Token, aber ein leeres. Das Zählmakro gibt also auch bei leerem Makroaufruf tatsächlich 1 statt 0 zurück. Wir können dieses Problem "leicht" beseitigen, wenn wir das Komma __VA_ARGS__ bedingt nach setzen , je nachdem , ob die Liste leer ist oder nicht:

#define NARG(...) ARG4_(__VA_ARGS__ COMMA(__VA_ARGS__) 4, 3, 2, 1, 0)

Das sah einfach aus, aber das COMMAMakro ist ziemlich schwer; Zum Glück wird das Thema bereits in einem Blog von Jens Gustedt behandelt (danke, Jens). Grundlegender Trick ist, dass Funktionsmakros nicht erweitert werden, wenn nicht Klammern folgen. Weitere Erklärungen finden Sie in Jens 'Blog. Wir müssen die Makros nur ein wenig an unsere Bedürfnisse anpassen (ich werde kürzere Namen verwenden und weniger Argumente für die Kürze).

#define ARGN(...) ARGN_(__VA_ARGS__)
#define ARGN_(_0, _1, _2, _3, N, ...) N
#define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 1, 0)

#define SET_COMMA(...) ,

#define COMMA(...) SELECT_COMMA             \
(                                           \
        HAS_COMMA(__VA_ARGS__),             \
        HAS_COMMA(__VA_ARGS__ ()),          \
        HAS_COMMA(SET_COMMA __VA_ARGS__),   \
        HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \
)

#define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3)
#define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 ## _1 ## _2 ## _3

#define COMMA_0000 ,
#define COMMA_0001
#define COMMA_0010 ,
// ... (all others with comma)
#define COMMA_1111 ,

Und jetzt geht es uns gut ...

Der vollständige Code in einem Block:

/*
 * demo.c
 *
 *  Created on: 2017-09-14
 *      Author: sboehler
 */

#include <stdio.h>

void foo_void(void)
{
    puts("void");
}
void foo_int(int c)
{
    printf("int: %d\n", c);
}
void foo_char(char c)
{
    printf("char: %c\n", c);
}
void foo_double(double c)
{
    printf("double: %.2f\n", c);
}
void foo_double_int(double c, int d)
{
    printf("double: %.2f, int: %d\n", c, d);
}

#define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__)

#define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__)
#define CONCAT(X, Y) CONCAT_(X, Y)
#define CONCAT_(X, Y) X ## Y

#define SELECT_0() foo_void
#define SELECT_1(_1) _Generic ((_1), \
        int: foo_int,                \
        char: foo_char,              \
        double: foo_double           \
)
#define SELECT_2(_1, _2) _Generic((_1), \
        double: _Generic((_2),          \
                int: foo_double_int     \
        )                               \
)

#define ARGN(...) ARGN_(__VA_ARGS__)
#define ARGN_(_0, _1, _2, N, ...) N

#define NARG(...) ARGN(__VA_ARGS__ COMMA(__VA_ARGS__) 3, 2, 1, 0)
#define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 0)

#define SET_COMMA(...) ,

#define COMMA(...) SELECT_COMMA             \
(                                           \
        HAS_COMMA(__VA_ARGS__),             \
        HAS_COMMA(__VA_ARGS__ ()),          \
        HAS_COMMA(SET_COMMA __VA_ARGS__),   \
        HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \
)

#define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3)
#define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 ## _1 ## _2 ## _3

#define COMMA_0000 ,
#define COMMA_0001
#define COMMA_0010 ,
#define COMMA_0011 ,
#define COMMA_0100 ,
#define COMMA_0101 ,
#define COMMA_0110 ,
#define COMMA_0111 ,
#define COMMA_1000 ,
#define COMMA_1001 ,
#define COMMA_1010 ,
#define COMMA_1011 ,
#define COMMA_1100 ,
#define COMMA_1101 ,
#define COMMA_1110 ,
#define COMMA_1111 ,

int main(int argc, char** argv)
{
    foo();
    foo(7);
    foo(10.12);
    foo(12.10, 7);
    foo((char)'s');

    return 0;
}

1

Können Sie nicht einfach C ++ und nicht alle anderen C ++ - Funktionen außer dieser verwenden?

Wenn immer noch kein nur striktes C, dann würde ich stattdessen verschiedene Funktionen empfehlen .


3
Nicht, wenn ein C ++ - Compiler für das Betriebssystem, für das er codiert, nicht verfügbar ist.
Brian

2
nicht nur das, sondern er möchte vielleicht einen C ABI, der keinen Namen enthält.
Spudd86


-4

Ich hoffe, der folgende Code hilft Ihnen, die Funktionsüberladung zu verstehen

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

int fun(int a, ...);
int main(int argc, char *argv[]){
   fun(1,10);
   fun(2,"cquestionbank");
   return 0;
}
int fun(int a, ...){
  va_list vl;
  va_start(vl,a);

  if(a==1)
      printf("%d",va_arg(vl,int));
   else
      printf("\n%s",va_arg(vl,char *));
}

2
Eine Antwort sollte erklären, was es tut und warum es funktioniert. Wenn nicht, wie kann es jemandem helfen, etwas zu verstehen?
underscore_d

Hier gibt es keine Überlastung.
Melpomene

va_end wurde nie aufgerufen
user2262111
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.