bk.*_*bk. 261
哇,每个人都是这样的悲观主义者.答案是肯定的.
这不是微不足道的:到最后,我们将拥有核心函数,支持结构,包装函数和包装函数周围的宏.在我的工作中,我有一组宏来自动化所有这些; 一旦你理解了流程,你就可以轻松地做到这一点.
我在其他地方写过这个,所以这里有一个详细的外部链接来补充这里的摘要:http://modelingwithdata.org/arch/00000022.htm
我们想转
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结构并认为他们正在做通常的事情:
#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非常棒,因为它非常简单,而且还有足够的空间来实现这一切.
Wim*_*ink 152
是.:-)但不是你想象的方式.
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.这是一个"不要重复自己"的解决方案,它可以帮助您避免复制/粘贴现有代码.
Eli*_*ght 134
并不是的.唯一的方法是编写一个varargs函数并手动填写调用者未传递的参数的默认值.
u0b*_*6ae 40
我们可以创建使用命名参数(仅)作为默认值的函数.这是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);                                                             
}    
C99标准定义了初始化中的后续名称会覆盖以前的项目.我们也可以有一些标准的位置参数,只需相应地改变宏和函数签名.默认值参数只能在命名参数样式中使用.
节目输出:
1 2 3 4 5 6 7 8 9 10 
2 3 4 
1 3 5 7 9
小智 22
OpenCV使用类似的东西:
/* 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));
如果用户不知道他应该写什么,这个技巧可能会有所帮助:

dmc*_*kee 13
简答:不.
稍微长一点的回答:有一个旧的,旧的解决方法,你传递一个你为可选参数解析的字符串:
int f(int arg1, double arg2, char* name, char *opt);
opt可能包含"name = value"对或其他东西,你可以称之为
n = f(2,3.0,"foo","plot=yes save=no");
显然这只是偶尔有用.通常,当您需要单个接口来实现一系列功能时.
您仍然可以在粒子物理代码中找到这种方法,这些代码由c ++中的专业程序编写(例如ROOT).它的主要优点是它可以几乎无限延长,同时保持兼容性.
Mic*_*urr 13
可能最好的方法(根据你的情况在你的情况下可能或不可能)是转向C++并将其用作"更好的C".您可以在不使用类,模板,运算符重载或其他高级功能的情况下使用C++.
这将为您提供具有函数重载和默认参数(以及您选择使用的任何其他功能)的C变体.如果你真的认真地只使用有限的C++子集,你就必须要有点自律.
很多人会说以这种方式使用C++是一个糟糕的主意,他们可能会有一个观点.但这只是一种观点; 我认为使用你熟悉的C++功能是有效的,而不必购买整个东西.我认为C++成功的一个重要原因在于它早期就被很多程序员用于这种方式.
Chr*_*utz 13
另一种选择使用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);
Dav*_*eri 10
另一个使用宏的技巧:
#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;
}
如果只传递一个参数,则b接收默认值(在本例中为 15)
不,但您可以考虑使用一组函数(或宏)来近似使用默认参数:
// 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
}
是的,使用 C99 的功能,您可以做到这一点。这不需要定义新的数据结构,也不需要函数在运行时决定如何调用它,也没有任何计算开销。
有关详细说明,请参阅我的帖子
http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/
延斯