Konvertieren einer C++-Bibliothek in ANSI C und es scheint, als ob ANSI C keine Standardwerte für Funktionsvariablen unterstützt, oder irre ich mich? Was ich will, ist so etwas wie
int funcName(int foo, bar* = NULL);
Ist das Überladen von Funktionen in ANSI C auch möglich?
Würde brauchen
const char* foo_property(foo_t* /* this */, int /* property_number*/);
const char* foo_property(foo_t* /* this */, const char* /* key */, int /* iter */);
Ich könnte sie natürlich einfach anders benennen, aber da ich an C++ gewöhnt bin, habe ich irgendwie das Überladen von Funktionen verwendet.
Nein, Standard C wird auch nicht unterstützt. Warum glauben Sie, dass Sie Ihren C++-Code in C konvertieren müssen? Das könnte ziemlich schwierig werden – ich hätte gedacht, dass das Schreiben von Wrappern der richtige Weg wäre, wenn Ihr C++ von C aus aufrufbar sein muss.
Trotzdem habe ich einen “Trick” gefunden, um dies zu tun, wenn Sie GCC verwenden (Bearbeitung Dezember 2020) oder jeder Compiler, der mit C++2a kompatibel ist – ja, es funktioniert mit ‘plain C’, da es sich um einen Pre-Compiler-Trick handelt-.
GCC hat eine praktische ##-Erweiterung für Variadic-Makros, mit der Sie ein Standardargument simulieren können.
Der Trick hat Einschränkungen: Er funktioniert nur für 1 Standardwert, und das Argument muss der letzte Ihrer Funktionsparameter sein.
Hier ist ein funktionierendes Beispiel.
#include <stdio.h>
#define SUM(a,...) sum( a, (5, ##__VA_ARGS__) )
int sum (a, b)
int a;
int b;
{
return a + b;
}
main()
{
printf("%d\n", SUM( 3, 7 ) );
printf("%d\n", SUM( 3 ) );
}
In diesem Fall definiere ich SUM als Aufruf zur Summe, wobei das zweite Standardargument 5 ist.
Wenn Sie mit 2 Argumenten aufrufen (erster Aufruf in main), würde dies wie folgt vorverarbeitet werden: sum( 3, (5, 7) );
Das heisst:
- 1. Argument ist 3
- Das zweite Argument ist das Ergebnis der Folge (5, 7) … was offensichtlich 7 ist!
Da gcc clever ist, hat dies keine Auswirkung auf die Laufzeit, da das erste Mitglied der Sequenz eine Konstante ist und nicht benötigt wird, es wird einfach zur Kompilierzeit verworfen.
Wenn Sie nur mit einem Argument aufrufen, entfernt die gcc-Erweiterung das VA_ARGS UND das führende Koma. Es wird also vorverarbeitet als:
summe( 3, (5 ) );
Somit gibt das Programm die erwartete Ausgabe aus:
10
8
Dies simuliert also perfekt (mit den üblichen Makroeinschränkungen) eine Funktion mit 2 Argumenten, wobei das letzte optional ist und ein Standardwert angewendet wird, falls nicht angegeben.
Bearbeiten
-a) Es funktioniert auch mit CLANG (und möglicherweise anderen Compilern)
-b) Eine Version, die sich NICHT über ungenutzte Argumente beschwert:
#define DEF_OR_ARG(z,a,arg,...) arg
#define SUM(a,...) sum( a, DEF_OR_ARG(,##__VA_ARGS__,__VA_ARGS__,5))
[Edit – October 2020] : Sie könnten auch das Neue ausprobieren __VA_OPT__
das wurde mit c++2a standardisiert (und sollte auch in normalem C funktionieren) anstelle von ##, das eine gcc-Erweiterung ist. Typische Verwendung ist __VA_OPT__(,)
das würde das Komma hinzufügen, wenn die Argumentliste nicht leer ist und ansonsten nichts ausgibt.
[Edit – December 2020] :
Also der obige Trick, mit __VA_OPT__
wird:
#define DEF_OR_ARG(value,...) value
#define SUM(a,...) sum( a, DEF_OR_ARG(__VA_ARGS__ __VA_OPT__(,) 5))
Im Gegensatz zum ‘Sequenz-Trick’, der sich über unbenutzte Variablen beschweren könnte, betrifft dies nur den Precompiler und ist besser lesbar.
Wenn SUM mit nur einem Argument aufgerufen wird, ...
ist leer und __VA_OPT__
gibt nichts aus, also DEF_OR_ARG(__VA_ARGS__ __VA_OPT(,) 5)
wird DEF_OR_ARG( 5)
Wenn SUM mit einem zweiten Argument aufgerufen wird, ...
ist dieses zweite Argument und __VA_OPT__
erweitert sich auf den angegebenen Wert, der ein Koma ist. In diesem Fall
DEF_OR_ARG(__VA_ARGS__ __VA_OPT(,) 5)
wird DEF_OR_ARG(second_argument_of_SUM , 5)
Nun der Ausbau von DEF_OR_ARG
das passiert. Dies ist einfach, da es nur das erste Argument berücksichtigt und den Rest einfach verwirft. Also, wann SUM
ohne zweites Argument aufgerufen wurde (erster Fall oben), das erste Argument to DEF_OR_ARG
ist unser Standardwert. In dem Fall gab es ein zweites Argument dazu SUM
wird es das erste Argument für DEF_OR_ARG
das wird darauf erweitert und verwirft den Standardwert, der jetzt das zweite Argument ist.
Versuche dies.
#include <stdio.h>
#include <stdarg.h>
/* print all non-negative args one at a time;
all args are assumed to be of int type */
void printargs(int arg1, ...)
{
va_list ap;
int i;
va_start(ap, arg1);
for (i = arg1; i >= 0; i = va_arg(ap, int))
printf("%d ", i);
va_end(ap);
putchar('\n');
}
int main(void)
{
printargs(5, 2, 14, 84, 97, 15, 24, 48, -1);
printargs(84, 51, -1);
printargs(-1);
printargs(1, -1);
return
0;
}
Es gibt eine Möglichkeit, so viele Standardparameter zu unterstützen, wie Sie benötigen, verwenden Sie einfach eine Struktur.
// Populate structure with var list and set any default values
struct FooVars {
int int_Var1 = 1; // One is the default value
char char_Command[2] = {"+"};
float float_Var2 = 10.5;
};
struct FooVars MainStruct;
//...
// Switch out any values needed, leave the rest alone
MainStruct.float_Var2 = 22.8;
Myfunc(MainStruct); // Call the function which at this point will add 1 to 22.8.
//...
void Myfunc( struct FooVars *MyFoo ) {
switch(MyFoo.char_Command) {
case '+':
printf("Result is %i %c %f.1 = %f\n" MyFoo.int_Var1, MyFoo.char_Command, MyFoo.float_Var2, (MyFoo.float_Var2 + MyFoo.int_Var1);
break;
case '*':
// Insert multiply here, you get the point...
break;
case '//':
// Insert divide here...
break;
}
}
Soweit ich weiß, unterstützt ANSI C das Überladen von Funktionen oder Standardargumente nicht direkt. Der Standardersatz für das Überladen besteht darin, dem Funktionsnamen Suffixe hinzuzufügen, die die Argumenttypen angeben. Beispielsweise bedeutet in OpenGL das Suffix „3fv“ an einem Funktionsnamen, dass die Funktion einen Vektor von drei Floats verwendet.
Standardargumente können als Sonderfall der Funktionsüberladung angesehen werden.
In ANSI C gibt es weder Standardwerte noch Funktionsüberladung, also müssen Sie es auf andere Weise lösen.
Sie können nicht so einfach, da C sie nicht unterstützt. Der einfachere Weg, um eine “falsche Überladung” zu erreichen, ist die Verwendung von Suffixen, wie bereits gesagt … Standardwerte könnten mit der Funktion “Variable Arguments” simuliert werden, indem die Anzahl der übergebenen Argumente angegeben und programmgesteuert fehlende eines als Standard angegeben wird, z.
aType aFunction(int nargs, ...)
{
// "initialization" code and vars
switch(nargs)
{
case 0:
// all to default values... e.g.
aVar1 = 5; // ...
break;
case 1:
aVar1 = va_arg(arglist, int); //...
// initialize aVar2, 3, ... to defaults...
break;
// ...
}
}
Auch das Überladen kann mit var args mit zusätzlichen Informationen simuliert werden, die hinzugefügt und übergeben werden müssen, und Extracode … im Grunde eine minimalistische objektorientierte Laufzeit reproduzieren … Eine andere Lösung (oder tatsächlich die gleiche, aber mit einem anderen Ansatz) könnte die Verwendung von Tags sein: jedes Argument ist ein Paar Argumenttyp + Argument (eine Vereinigung des gesamten Satzes möglicher Argumenttypen), es gibt ein spezielles Terminator-Tag (Sie müssen nicht angeben, wie viele Argumente Sie übergeben), und natürlich benötigen Sie immer “Zusammenarbeit” von der Funktion, die Sie aufrufen, dh sie muss zusätzlichen Code enthalten, um die Tags zu analysieren und die eigentlich auszuführende Funktion auszuwählen (sie verhält sich wie eine Art Dispatcher).
Nein, es unterstützt nichts davon.
– Artefakt
7. Juni 2010 um 8:38 Uhr