C默认参数 有没有一种方法可以在C中定义函数的默认参数? 不,这是C++语言的特性。 < P> 简短答案:No.

C默认参数 有没有一种方法可以在C中定义函数的默认参数? 不,这是C++语言的特性。 < P> 简短答案:No.,c,arguments,default-parameters,C,Arguments,Default Parameters,稍长一点的回答:有一个古老的解决方法,您可以在其中传递为可选参数解析的字符串: int f(int arg1, double arg2, char* name, char *opt); 其中opt可能包括“name=value”对或其他东西,您可以像这样调用它 n = f(2,3.0,"foo","plot=yes save=no"); 显然,这只是偶尔有用。通常,当您需要一个单一的接口来实现一系列功能时 你仍然在粒子物理代码中找到这种方法,它是由C++中的专业程序编写的(比如说)。它的主

稍长一点的回答:有一个古老的解决方法,您可以在其中传递为可选参数解析的字符串:

int f(int arg1, double arg2, char* name, char *opt);
其中opt可能包括“name=value”对或其他东西,您可以像这样调用它

n = f(2,3.0,"foo","plot=yes save=no");
显然,这只是偶尔有用。通常,当您需要一个单一的接口来实现一系列功能时


你仍然在粒子物理代码中找到这种方法,它是由C++中的专业程序编写的(比如说)。它的主要优点是,它几乎可以无限期地扩展,同时保持后端兼容性。


即使是最新的C99标准也不支持这一点。

不太支持。唯一的方法是为调用者未通过的参数手动输入默认值。

否。

是。:-)但不是以你所期望的方式

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");
}

不幸的是,C不允许您重载方法,因此最终会得到两个不同的函数。不过,通过调用f2,您实际上是在使用默认值调用f1。这是一个“不重复自己”的解决方案,它帮助您避免复制/粘贴现有代码。

不,但是您可以考虑使用一组函数(或宏)来近似使用默认的ARG:

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

通常不会,但在gcc中,可以使用宏将funcA()的最后一个参数设置为可选

在funcB()中,我使用一个特殊值(-1)来表示需要“b”参数的默认值

#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) );
}
#包括
int funcA(inta,intb,…{返回a+b;}
#定义funcA(a,…)funcA(a,###(u)VA(u)ARGS(u),8)
int funcB(int a,int b){
如果(b==-1)b=8;
返回a+b;
}
内部主(空){
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));
}

<>代码>

可能是最好的方法(根据你的情况,在你的情况下可能或不可能)是移动到C++,并将其用作“更好的C”。可以使用C++而不使用类、模板、运算符重载或其他高级特性。 这将为您提供一个带有函数重载和默认参数(以及您选择使用的任何其他特性)的C变体。如果你真的只使用C++的限制子集,就必须稍微遵守纪律。< /P>


很多人会说用C++来这样做是个可怕的想法,他们可能有一个观点。但这只是一种观点;我认为使用C++的特性是很有效的,你可以不需要购买整个东西。我认为C++之所以成功的一个重要原因是它在早期就被很多程序员所使用。

< P>另一个选项使用<代码>结构> <代码>:< /P>
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);

是的,你可以在simulair做一些事情,这里你必须知道你可以得到的不同的参数列表,但是你有相同的函数来处理所有这些

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

哇,这里的每个人都这么悲观。答案是肯定的

这并不简单:到最后,我们将有一个核心函数、一个支持结构、一个包装函数和一个宏 围绕包装器函数。在我的工作中,我有一套宏来自动化所有这些;一旦 你了解流程,这样做对你来说很容易

我在其他地方写过,这里有一个详细的外部链接来补充这里的总结:

我们想转身

double f(int i, double x)
进入一个采用默认值(i=8,x=3.14)的函数。定义伴随结构:

typedef struct {
    int i;
    double x;
} f_args;
重命名函数
f_base
,并定义一个设置默认值和调用的包装函数 基地:

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);
}
现在使用C的可变宏添加一个宏。这样用户就不必知道他们 实际填充一个
f_args
struct,并认为他们在做通常的事情:

#define f(...) var_f((f_args){__VA_ARGS__});
好的,下面所有的步骤都可以:

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
检查关于复合初始值设定项如何为确切规则设置默认值的规则

有一件事是行不通的:
f(0)
,因为我们无法区分缺少的值和 零。根据我的经验,这是一件需要注意的事情,但也可以作为一件事来处理 需要的是——你的默认值有一半是零

我费了好大劲才写出来,因为我认为命名参数和默认值 真的使C语言的编码更容易,甚至更有趣。及
C非常简单,而且仍然有足够的空间使这一切成为可能。

是的,有了C99的功能,你可以做到这一点。这种方法不需要定义新的数据结构,也不需要函数在运行时决定如何调用它,以及 没有任何计算开销

有关详细说明,请参阅我在


Jens

我们可以创建使用命名参数(仅)作为默认值的函数。这是bk.答案的延续

#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);                                                             
}    
使用类似于:

/* 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));
如果用户不知道他应该写什么,这个技巧会很有帮助:

为什么我们不能这样做呢

为可选参数指定默认值。这样,函数的调用方就不必传递参数的值。参数采用默认值。 对于客户端来说,该参数很容易成为可选参数

例如

void foo(inta,intb=0)


这里b是一个可选参数。

我改进了Jens Gustedt的参数,以便:

  • 没有使用内联函数
  • 默认值在预处理期间计算
  • 模块化可重用宏
  • 可以设置编译器错误,以有意义地匹配允许的默认值的参数不足的情况
  • 如果参数类型保持明确,则不需要使用默认值来形成参数列表的尾部
  • 与C11 _泛型的互点
  • 改变
    /* 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));
    
    #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
    
    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__)
    
    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__))
    
    // 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__)
    
    #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);
    }
    
    #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);
    }
    
    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;
    }
    
    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  
    
    #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;
    }