Как создать функцию в С, которая может принимать как 2 аргумента, так и 3?

Есть функция bar(const char *a, struct my_struct1 b, struct my_struct2 c), как сделать так, чтобы эту функцию можно было вызывать от двух аргументов, то есть так: bar(const char *a, struct my_struct1 b)?


Ответы (2 шт):

Автор решения: Sergey

Можно воспользоваться макросом va_arg библиотеки stdarg.h.

https://learnc.info/c/vararg_functions.html

→ Ссылка
Автор решения: AlexGlebe

Можно попробовать библиотеку с переменным количеством аргументов. Но в этом случае определить дали аргумент или нет можно только с помощью передачи нулевого указателя.

// -Wall -Wextra -Wpedantic --std=c11 -Winline 
#include <stdarg.h>

typedef int calc_result ;
typedef int(*calc_function)(int) ;

int calc_evaluate(const char *buffer, calc_result *res, ... /*calc_function functions[]*/){
    va_list arguments;
    va_start ( arguments, res );
    calc_function * functions = va_arg ( arguments, calc_function * );
    if ( functions )
      /* если аргумент есть */ ;
    else 
      /* если указатель нулевой */ ;
    va_end ( arguments );
}

calc_evaluate("",&res,(calc_function*)0);

А если хочется два варианта : без третьего указателя или с третим нулевым, то и приходим опять к началу вопроса.

В одиннадцатом стандарте можно определить функции с одним именем но с разным типом аргумента.

int calc_evaluate(const char *buffer, calc_result *res,
  calc_function functions[]);
int calc_evaluatev(const char *buffer, calc_result *res);

#define calc_evaluate2t(X,Y,Z)          \
  _Generic(   (Z),       \
    calc_function * : calc_evaluate(X,Y,Z) , \
    int * : calc_evaluatev(X,Y) )

calc_evaluate2t("",&res,(int*)0);
calc_evaluate2t("",&res,functions);

Но к макросу и к Generic нужно предложить третий аргумент чтобы определить тип. Опять пришли к тому-же.

Есть способ передавать аргументы в функцию с помощью одной структуры разного типа. Но эти типы нужно объявлять и писанины будет много.

typedef
    struct  {
        const char *buffer;
        calc_result *res;
    }   args2 ;

typedef
    struct  {
        const char *buffer;
        calc_result *res;
        calc_function * functions ;
    }   args3 ;

int calc_evaluate2(args2);
int calc_evaluate3(args3);

#define calc_evaluatet(X)          \
    _Generic(   (X),       \
        args2: calc_evaluate2,       \
        args3: calc_evaluate3 )(X)

calc_evaluatet(((args2){"",&res}));
calc_evaluatet(((args3){"",&res,functions}));

Имя типа структур нужно задавать вручную и писанины опять много лишней.

Не проще ли вам сделать две функции с разным именем?

int calc_evaluateN(const char *buffer, calc_result *res) ;
int calc_evaluateF(const char *buffer, calc_result *res,
  calc_function functions[]);
→ Ссылка