Frage

Gibt es eine Möglichkeit, Standardargumente für eine Funktion in C anzugeben?

War es hilfreich?

Lösung

Nicht wirklich. Der einzige Weg wäre href="https://en.wikipedia.org/wiki/Variadic_function#Example_in_C" zum eine varargs Funktion schreiben und manuell in die Standardwerte für Argumente füllen die wird der Anrufer nicht passieren.

Andere Tipps

Wow, jeder ist so ein Pessimist hier herum. Die Antwort ist ja.

Es ist nicht trivial: Bis Ende, wir werden die Kernfunktion haben, eine unterstützende Struktur, eine Wrapper-Funktion, und einen Makro um die Wrapper-Funktion. In meiner Arbeit habe ich eine Reihe von Makros all dies zu automatisieren; Einmal Sie verstehen die Strömung es wird einfach für Sie das gleiche zu tun.

Ich habe das an anderer Stelle geschrieben, so ist hier eine detaillierte externer Link die Zusammenfassung hier zu ergänzen: http: //modelingwithdata.org/arch/00000022.htm

Wir möchten Sie

double f(int i, double x)

in eine Funktion, die Standardwerte (i = 8, x = 3,14) hat. Definieren Sie einen Begleiter Struktur:

typedef struct {
    int i;
    double x;
} f_args;

Benennen Sie Ihre Funktion f_base und definieren eine Wrapper-Funktion, die Standardwerte und Anrufe setzt die Basis:

double var_f(f_args in){
    int i_out = in.i ? in.i : 8;
    double x_out = in.x ? in.x : 3.14;
    return f_base(i_out, x_out);
}

Jetzt ein Makro hinzufügen, C-Schema variadische Makros. Auf diese Weise müssen Benutzer nicht wissen, sie sind tatsächlich eine f_args struct bevölkern und denken, dass sie die üblichen tun:

#define f(...) var_f((f_args){__VA_ARGS__});

OK, jetzt alle folgenden funktionieren würde:

f(3, 8);      //i=3, x=8
f(.i=1, 2.3); //i=1, x=2.3
f(2);         //i=2, x=3.14
f(.x=9.2);    //i=8, x=9.2

Überprüfen Sie die Regeln, wie Verbindung initializers Standardeinstellungen für die genauen Regeln.

Eine Sache, die nicht funktionieren: f(0), weil wir nicht zwischen einem fehlenden Wert unterscheiden können und Null. Meiner Erfahrung nach ist dies etwas zu achten, aber darauf geachtet werden, kann als Bedarf --- die Hälfte der Zeit wirklich Ihr Standard-Null ist.

Ich ging durch die Mühe des Schreibens dieses, weil ich denke, benannte Argumente und Vorgaben  wirklich machen in C Codierung einfacher und noch mehr Spaß. Und C ist genial für so einfach zu sein und immer noch genug, um es mit allen möglich, dies zu machen.

Ja. :-) Aber nicht in einer Art und Weise, die Sie erwarten.

int f1(int arg1, double arg2, char* name, char *opt);

int f2(int arg1, double arg2, char* name)
{
  return f1(arg1, arg2, name, "Some option");
}

Leider ist C nicht zulassen, dass Sie Methoden, um eine Überlastung, so dass Sie mit zwei verschiedenen Funktionen würden am Ende. Dennoch von f2 Aufruf, würden Sie tatsächlich mit einem Standardwert Aufruf f1 sein. Dies ist eine „Do not Repeat Yourself“ Lösung, die Sie mit dem Kopieren / Einfügen vorhandenen Code zu vermeiden hilft.

Wir können Funktionen erstellen, die Parameter namens verwenden (nur) für Standardwerte. Dies ist eine Fortsetzung von bk. Antwort.

#include <stdio.h>                                                               

struct range { int from; int to; int step; };
#define range(...) range((struct range){.from=1,.to=10,.step=1, __VA_ARGS__})   

/* use parentheses to avoid macro subst */             
void (range)(struct range r) {                                                     
    for (int i = r.from; i <= r.to; i += r.step)                                 
        printf("%d ", i);                                                        
    puts("");                                                                    
}                                                                                

int main() {                                                                     
    range();                                                                    
    range(.from=2, .to=4);                                                      
    range(.step=2);                                                             
}    

Der C99-Standard legt fest, dass später Name in der Initialisierung vorherige Elemente außer Kraft setzen. Wir können auch auch einige Standard-Positionsparameter haben, ändern Sie einfach die Makro- und Funktionssignatur entsprechend. Der Standardwert Parameter können nur im benannten Parameter Stil verwendet werden.

Programmausgang:

1 2 3 4 5 6 7 8 9 10 
2 3 4 
1 3 5 7 9

OpenCV nutzt so etwas wie:

/* in the header file */

#ifdef __cplusplus
    /* in case the compiler is a C++ compiler */
    #define DEFAULT_VALUE(value) = value
#else
    /* otherwise, C compiler, do nothing */
    #define DEFAULT_VALUE(value)
#endif

void window_set_size(unsigned int width  DEFAULT_VALUE(640),
                     unsigned int height DEFAULT_VALUE(400));

Wenn der Benutzer nicht weiß, was er schreiben soll, kann dieser Trick hilfreich sein:

Anwendungsbeispiel

Nein.

Nicht einmal der neueste C99-Standard dies unterstützt.

Nein, das ist eine C ++ Funktion.

Wahrscheinlich den besten Weg, dies zu tun (was kann oder auch auf Ihrer Situation in Ihrem Fall nicht möglich sein, abhängig) bis C bewegen ++ und verwenden Sie es als ‚ein besseres C‘. Sie können C ++ verwenden, ohne die Verwendung von Klassen, Vorlagen, Überladen von Operatoren oder andere erweiterte Funktionen.

Dies gibt Ihnen eine Variante C mit Überladen von Funktionen und Standardparameter (und was auch immer andere Funktionen, die Sie verwenden gewählt haben). Sie müssen nur ein wenig diszipliniert sein, wenn Sie wirklich ernsthaft über nur eine begrenzte Teilmenge von C ++ verwendet wird.

Eine Menge Leute werden sagen, dass es eine schreckliche Idee ist C ++ auf diese Weise, und sie könnten einen Punkt haben. Aber ist es nur eine Meinung; Ich denke, es gültig ist Features von C ++ zu verwenden, die Sie bequem mit, ohne in die ganze Sache kaufen zu müssen. Ich denke, dass ein wesentlicher Teil des Grundes für den Erfolg von C ++ ist, dass es durch eine ganze Menge von Programmierern verwendet wurde in es genau frühe Tagen ist auf diese Weise.

Kurze Antwort: NEIN.

Etwas längere Antwort: Es gibt ein altes, alt Problemumgehung, bei der Sie eine Zeichenfolge übergeben, die Sie benötigen analysieren für optionale Argumente:

int f(int arg1, double arg2, char* name, char *opt);

wobei opt das Paar „name=value“ oder etwas anderes enthalten kann und das Sie wie folgt nennen würden

n = f(2,3.0,"foo","plot=yes save=no");

Offensichtlich ist dies nur gelegentlich nützlich.Im Allgemeinen, wenn Sie eine einzelne Schnittstelle zu einer Funktionsfamilie benötigen.


Diesen Ansatz findet man immer noch in Teilchenphysik-Codes, die von professionellen Programmen in C++ geschrieben werden (wie z. B WURZEL).Der Hauptvorteil besteht darin, dass es nahezu unbegrenzt erweiterbar ist und gleichzeitig die Abwärtskompatibilität gewahrt bleibt.

Eine weitere Option verwendet structs:

struct func_opts {
  int    arg1;
  char * arg2;
  int    arg3;
};

void func(int arg, struct func_opts *opts)
{
    int arg1 = 0, arg3 = 0;
    char *arg2 = "Default";
    if(opts)
      {
        if(opts->arg1)
            arg1 = opts->arg1;
        if(opts->arg2)
            arg2 = opts->arg2;
        if(opts->arg3)
            arg3 = opts->arg3;
      }
    // do stuff
}

// call with defaults
func(3, NULL);

// also call with defaults
struct func_opts opts = {0};
func(3, &opts);

// set some arguments
opts.arg3 = 3;
opts.arg2 = "Yes";
func(3, &opts);

Nein.

Nein

, aber Sie könnten prüfen, mit einem gesetzt von Funktionen (oder Makros) zur Annäherung mit dem Standard argumenten:

// No default args
int foo3(int a, int b, int c)
{
    return ...;
}

// Default 3rd arg
int foo2(int a, int b)
{
    return foo3(a, b, 0);  // default c
}

// Default 2nd and 3rd args
int foo1(int a)
{
    return foo3(a, 1, 0);  // default b and c
}

Ja, mit Eigenschaften von C99 Sie können dies tun. Dies funktioniert ohne neue Datenstrukturen zu definieren, oder so und ohne die Funktion zur Laufzeit zu entscheiden hat, wie es genannt wurde, und ohne Rechenaufwand.

siehe

Für eine detaillierte Erklärung meines Beitrag bei

http://gustedt.wordpress.com/ 2010/06/03 / default-Argumente-for-c99 /

Jens

Generell nein, aber in gcc können Sie die letzten Parameter von funcA machen () optional mit einem Makro.

In funcB () i verwenden, um einen speziellen Wert (-1), um zu signalisieren, dass ich den Standardwert für die 'b' Parameter muß.

#include <stdio.h> 

int funcA( int a, int b, ... ){ return a+b; }
#define funcA( a, ... ) funcA( a, ##__VA_ARGS__, 8 ) 


int funcB( int a, int b ){
  if( b == -1 ) b = 8;
  return a+b;
}

int main(void){
  printf("funcA(1,2): %i\n", funcA(1,2) );
  printf("funcA(1):   %i\n", funcA(1)   );

  printf("funcB(1, 2): %i\n", funcB(1, 2) );
  printf("funcB(1,-1): %i\n", funcB(1,-1) );
}

I verbessert Jens Gustedt beantworten so dass:

  1. Inline-Funktionen nicht verwendet werden
  2. Standardwerte werden im Vorlauf
  3. berechnet
  4. modular wiederverwendbarer Makros
  5. möglich Compiler-Fehler zu setzen, die Bedeutung der bei ungenügender Argumente für die zulässigen Vorgaben übereinstimmt
  6. die Standardwerte werden nicht, wenn die Argumenttypen eindeutig bleiben erforderlich, um das Ende der Parameterliste zu bilden
  7. interopts mit C11 _Generic
  8. variieren, um die Funktionsnamen durch die Anzahl der Argumente!

variadic.h:

#ifndef VARIADIC

#define _NARG2(_0, _1, _2, ...) _2
#define NUMARG2(...) _NARG2(__VA_ARGS__, 2, 1, 0)
#define _NARG3(_0, _1, _2, _3, ...) _3
#define NUMARG3(...) _NARG3(__VA_ARGS__, 3, 2, 1, 0)
#define _NARG4(_0, _1, _2, _3, _4, ...) _4
#define NUMARG4(...) _NARG4(__VA_ARGS__, 4, 3, 2, 1, 0)
#define _NARG5(_0, _1, _2, _3, _4, _5, ...) _5
#define NUMARG5(...) _NARG5(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define _NARG6(_0, _1, _2, _3, _4, _5, _6, ...) _6
#define NUMARG6(...) _NARG6(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0)
#define _NARG7(_0, _1, _2, _3, _4, _5, _6, _7, ...) _7
#define NUMARG7(...) _NARG7(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
#define _NARG8(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) _8
#define NUMARG8(...) _NARG8(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define _NARG9(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
#define NUMARG9(...) _NARG9(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define __VARIADIC(name, num_args, ...) name ## _ ## num_args (__VA_ARGS__)
#define _VARIADIC(name, num_args, ...) name (__VARIADIC(name, num_args, __VA_ARGS__))
#define VARIADIC(name, num_args, ...) _VARIADIC(name, num_args, __VA_ARGS__)
#define VARIADIC2(name, num_args, ...) __VARIADIC(name, num_args, __VA_ARGS__)

// Vary function name by number of arguments supplied
#define VARIADIC_NAME(name, num_args) name ## _ ## num_args ## _name ()
#define NVARIADIC(name, num_args, ...) _VARIADIC(VARIADIC_NAME(name, num_args), num_args, __VA_ARGS__)

#endif

Vereinfachte Verwendungsszenario:

const uint32*
uint32_frombytes(uint32* out, const uint8* in, size_t bytes);

/*
The output buffer defaults to NULL if not provided.
*/

#include "variadic.h"

#define uint32_frombytes_2(   b, c) NULL, b, c
#define uint32_frombytes_3(a, b, c)    a, b, c
#define uint32_frombytes(...) VARIADIC(uint32_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

Und mit _Generic:

const uint8*
uint16_tobytes(const uint16* in, uint8* out, size_t bytes);

const uint16*
uint16_frombytes(uint16* out, const uint8* in, size_t bytes);

const uint8*
uint32_tobytes(const uint32* in, uint8* out, size_t bytes);

const uint32*
uint32_frombytes(uint32* out, const uint8* in, size_t bytes);

/*
The output buffer defaults to NULL if not provided.
Generic function name supported on the non-uint8 type, except where said type
is unavailable because the argument for output buffer was not provided.
*/

#include "variadic.h"

#define   uint16_tobytes_2(a,    c) a, NULL, c
#define   uint16_tobytes_3(a, b, c) a,    b, c
#define   uint16_tobytes(...) VARIADIC(  uint16_tobytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define uint16_frombytes_2(   b, c) NULL, b, c
#define uint16_frombytes_3(a, b, c)    a, b, c
#define uint16_frombytes(...) VARIADIC(uint16_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define   uint32_tobytes_2(a,    c) a, NULL, c
#define   uint32_tobytes_3(a, b, c) a,    b, c
#define   uint32_tobytes(...) VARIADIC(  uint32_tobytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define uint32_frombytes_2(   b, c) NULL, b, c
#define uint32_frombytes_3(a, b, c)    a, b, c
#define uint32_frombytes(...) VARIADIC(uint32_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define   tobytes(a, ...) _Generic((a),                                                                                                 \
                                   const uint16*: uint16_tobytes,                                                                       \
                                   const uint32*: uint32_tobytes)  (VARIADIC2(  uint32_tobytes, NUMARG3(a, __VA_ARGS__), a, __VA_ARGS__))

#define frombytes(a, ...) _Generic((a),                                                                                                 \
                                         uint16*: uint16_frombytes,                                                                     \
                                         uint32*: uint32_frombytes)(VARIADIC2(uint32_frombytes, NUMARG3(a, __VA_ARGS__), a, __VA_ARGS__))

Und mit variadische Funktionsnamen Auswahl, die mit _Generic werden kann nicht kombiniert:

// winternitz() with 5 arguments is replaced with merkle_lamport() on those 5 arguments.

#define   merkle_lamport_5(a, b, c, d, e) a, b, c, d, e
#define   winternitz_7(a, b, c, d, e, f, g) a, b, c, d, e, f, g
#define   winternitz_5_name() merkle_lamport
#define   winternitz_7_name() winternitz
#define   winternitz(...) NVARIADIC(winternitz, NUMARG7(__VA_ARGS__), __VA_ARGS__)

Ein weiterer Trick, mit Hilfe von Makros:

#include <stdio.h>

#define func(...) FUNC(__VA_ARGS__, 15, 0)
#define FUNC(a, b, ...) func(a, b)

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

int main(void)
{
    printf("%d\n", func(1));
    printf("%d\n", func(1, 2));
    return 0;
}

Wenn nur ein Argument übergeben wird, b erhält den Standardwert (in diesem Fall 15)

Ja, Sie etwas Ähnliches tun können, müssen Sie hier die unterschiedlichen Argumentlisten wissen Sie bekommen können, aber sie haben die gleiche Funktion, sie alle zu behandeln.

typedef enum { my_input_set1 = 0, my_input_set2, my_input_set3} INPUT_SET;

typedef struct{
    INPUT_SET type;
    char* text;
} input_set1;

typedef struct{
    INPUT_SET type;
    char* text;
    int var;
} input_set2;

typedef struct{
    INPUT_SET type;
    int text;
} input_set3;

typedef union
{
    INPUT_SET type;
    input_set1 set1;
    input_set2 set2;
    input_set3 set3;
} MY_INPUT;

void my_func(MY_INPUT input)
{
    switch(input.type)
    {
        case my_input_set1:
        break;
        case my_input_set2:
        break;
        case my_input_set3:
        break;
        default:
        // unknown input
        break;
    }
}

YES

Durch Makros

3 Parameter:

#define my_func2(...) my_func3(__VA_ARGS__, 0.5)
#define my_func1(...) my_func2(__VA_ARGS__, 10)
#define VAR_FUNC(_1, _2, _3, NAME, ...) NAME
#define my_func(...) VAR_FUNC(__VA_ARGS__, my_func3, my_func2, my_func1)(__VA_ARGS__)

void my_func3(char a, int b, float c) // b=10, c=0.5
{
    printf("a=%c; b=%d; c=%f\n", a, b, c);
}

Wenn Sie vierte Argument wollen, dann eine zusätzliche my_func3 muss hinzugefügt werden. Beachten Sie die Änderungen in VAR_FUNC, my_func2 und my_func

4 Parameter:

#define my_func3(...) my_func4(__VA_ARGS__, "default") // <== New function added
#define my_func2(...) my_func3(__VA_ARGS__, (float)1/2)
#define my_func1(...) my_func2(__VA_ARGS__, 10)
#define VAR_FUNC(_1, _2, _3, _4, NAME, ...) NAME
#define my_func(...) VAR_FUNC(__VA_ARGS__, my_func4, my_func3, my_func2, my_func1)(__VA_ARGS__)

void my_func4(char a, int b, float c, const char* d) // b=10, c=0.5, d="default"
{
    printf("a=%c; b=%d; c=%f; d=%s\n", a, b, c, d);
}

Nur Ausnahme, dass float Variablen können keine Standardwerte angegeben werden (, es sei denn, wenn es das letzte Argument, wie in dem 3 Parameter Fall ), weil sie Zeit brauchen (‘. ‚), die innerhalb von Makro Argumente nicht akzeptiert wird. Aber kann um eine Arbeit, herauszufinden, wie in my_func2 Makro gesehen ( von 4 Parametern Fall )

Programm

int main(void)
{
    my_func('a');
    my_func('b', 20);
    my_func('c', 200, 10.5);
    my_func('d', 2000, 100.5, "hello");

    return 0;
}

Ausgabe:

a=a; b=10; c=0.500000; d=default                                                                                                                                                  
a=b; b=20; c=0.500000; d=default                                                                                                                                                  
a=c; b=200; c=10.500000; d=default                                                                                                                                                
a=d; b=2000; c=100.500000; d=hello  

Warum können wir nicht tun.

Geben Sie das optionale Argumente einen Standardwert. Auf diese Weise kann der Anrufer die Funktion nicht unbedingt den Wert des Arguments zu übergeben. Das Argument ist der Standardwert. Und leicht das Argument wird für die Kunden optional.

Für z.

void foo (int a, int b = 0);

Hier b ist ein optionales Argument.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top