Standardwerte für Argumente in C-Funktionen und Funktionsüberladung in C

Lesezeit: 7 Minuten

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, es unterstützt nichts davon.

    – Artefakt

    7. Juni 2010 um 8:38 Uhr

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.

  • Ich arbeite jetzt in einer C-Umgebung und die Verwendung von C++-Code wurde verboten ;)… Anstatt also das vorhandene C mit dem g++-Compiler kompatibel zu machen und somit C++-Klassen neben dem C-Code verwenden zu können, bin ich Ich bin gezwungen, vorhandene nützliche Klassen nach C zu konvertieren.

    – inquam

    7. Juni 2010 um 8:42 Uhr

  • @ inquam: Nicht. Verwenden Sie die vorhandene Sprache, versuchen Sie nicht, dem Compiler eine andere Sprache aufzuzwingen. Während es vergleichsweise einfach ist, C-Code in einer C++-Umgebung zum Laufen zu bringen, ist das Gegenteil alles andere als trivial (wie Sie gerade festgestellt haben). Implementieren Sie lieber Ihre “nützlichen Klassen” als C-Funktionsbibliothek, als zu versuchen, sie 1:1 zu “portieren”.

    – DevSolar

    7. Juni 2010 um 9:07 Uhr

  • @inquam Im Allgemeinen stimme ich DevSolar zu. Insbesondere, wenn Sie C++-Features wie Container der Standardbibliothek, Ausnahmen und insbesondere RAII verwendet haben. Wenn Ihr ursprünglicher Code C++ jedoch einfach als “ein besseres C” bezeichnet, dann denke ich, dass es gerade noch machbar ist, obwohl ich nicht derjenige sein möchte, der es tut.

    anon

    7. Juni 2010 um 9:11 Uhr

  • Diese spezielle Bibliothek wurde unter Verwendung von Zeichenfolgen und Arrays im C-Stil geschrieben, sodass keine STL beteiligt war. Damit es funktioniert (was ich jetzt habe), ging es im Grunde darum, die Klassenstruktur zu entfernen und Funktionen zu erstellen, die das ursprünglich erstellte Objekt an jede Klasse übergeben. Eine “neue” Funktion, um das Objekt zu erstellen und diese dann als eines der Argumente für alle anderen Funktionen zu verwenden.

    – inquam

    7. Juni 2010 um 13:41 Uhr

Benutzer-Avatar
Benutzer941239

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 SUMwird 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.

Benutzer-Avatar
Hans Insulander

In ANSI C gibt es weder Standardwerte noch Funktionsüberladung, also müssen Sie es auf andere Weise lösen.

Benutzer-Avatar
Shin Takezou

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).

1366130cookie-checkStandardwerte für Argumente in C-Funktionen und Funktionsüberladung in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy