C 默认参数
有没有办法为 C 中的函数指定默认参数?
Is there a way to specify default arguments to a function in C?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
有没有办法为 C 中的函数指定默认参数?
Is there a way to specify default arguments to a function in C?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(24)
哇,这里的每个人都是如此悲观主义者。答案是肯定的。
这并不简单:到最后,我们将拥有核心函数、支持结构、包装函数和宏
围绕包装函数。在我的工作中,我有一组宏来自动化这一切;一次
如果您了解了流程,那么您就可以轻松执行相同的操作。
我已在其他地方写过此内容,因此这里有一个详细的外部链接来补充此处的摘要: http://modelingwithdata .org/arch/00000022.htm
我们希望变成
一个采用默认值(i=8,x=3.14)的函数。定义一个伴随结构:
重命名您的函数
f_base
,并定义一个设置默认值和调用的包装函数基础:
现在添加一个宏,使用 C 的可变参数宏。这样用户就不必知道他们是
实际上填充一个
f_args
结构并认为它们正在做通常的事情:好的,现在以下所有操作都可以工作:
检查有关复合初始值设定项如何为确切规则设置默认值的规则。
有一点不起作用:
f(0)
,因为我们无法区分缺失值和缺失值零。根据我的经验,这是需要注意的事情,但可以按照以下方式处理:
需求出现了——有一半的时间你的默认值实际上是零。
我在写这篇文章时遇到了麻烦,因为我认为命名参数和默认值
确实让 C 语言编码变得更容易、更有趣。和
C 的伟大之处在于它如此简单,而且仍然有足够的能力使这一切成为可能。
Wow, everybody is such a pessimist around here. The answer is yes.
It ain't trivial: by the end, we'll have the core function, a supporting struct, a wrapper function, and a macro
around the wrapper function. In my work I have a set of macros to automate all this; once
you understand the flow it'll be easy for you to do the same.
I've written this up elsewhere, so here's a detailed external link to supplement the summary here: http://modelingwithdata.org/arch/00000022.htm
We'd like to turn
into a function that takes defaults (i=8, x=3.14). Define a companion struct:
Rename your function
f_base
, and define a wrapper function that sets defaults and callsthe base:
Now add a macro, using C's variadic macros. This way users don't have to know they're
actually populating a
f_args
struct and think they're doing the usual:OK, now all of the following would work:
Check the rules on how compound initializers set defaults for the exact rules.
One thing that won't work:
f(0)
, because we can't distinguish between a missing value andzero. In my experience, this is something to watch out for, but can be taken care of as
the need arises---half the time your default really is zero.
I went through the trouble of writing this up because I think named arguments and defaults
really do make coding in C easier and even more fun. And
C is awesome for being so simple and still having enough there to make all this possible.
是的。 :-) 但不是以您期望的方式。
不幸的是,C 不允许您重载方法,因此您最终会得到两个不同的函数。不过,通过调用 f2,您实际上会使用默认值调用 f1。这是一个“不要重复自己”的解决方案,它可以帮助您避免复制/粘贴现有代码。
Yes. :-) But not in a way you would expect.
Unfortunately, C doesn't allow you to overload methods so you'd end up with two different functions. Still, by calling f2, you'd actually be calling f1 with a default value. This is a "Don't Repeat Yourself" solution, which helps you to avoid copying/pasting existing code.
并不真地。唯一的方法是编写一个可变参数函数并手动填写参数的默认值呼叫者没有通过。
Not really. The only way would be to write a varargs function and manually fill in default values for arguments which the caller doesn't pass.
我们可以创建(仅)使用命名参数作为默认值的函数。这是 bk. 答案的延续。
C99 标准定义初始化中后面的名称会覆盖前面的项目。我们也可以有一些标准的位置参数,只需相应地更改宏和函数签名即可。默认值参数只能用于命名参数样式。
程序输出:
We can create functions which use named parameters (only) for default values. This is a continuation of bk.'s answer.
The C99 standard defines that later names in the initialization override previous items. We can also have some standard positional parameters as well, just change the macro and function signature accordingly. The default value parameters can only be used in named parameter style.
Program output:
OpenCV 使用类似以下内容:
如果用户不知道应该写什么,这个技巧会很有帮助:
OpenCV uses something like:
If the user doesn't know what he should write, this trick can be helpful:
不。
即使是最新的 C99 标准也不支持这一点。
No.
Not even the very latest C99 standard supports this.
不,这是 C++ 语言的功能。
No, that's a C++ language feature.
也许最好的方法是转向 C++ 并将其用作“更好的 C”(根据您的具体情况,这可能会也可能不会)。您可以在不使用类、模板、运算符重载或其他高级功能的情况下使用 C++。
这将为您提供带有函数重载和默认参数(以及您选择使用的任何其他功能)的 C 变体。如果您真的很认真地只使用 C++ 的有限子集,那么您只需要遵守一点纪律即可。
很多人会说以这种方式使用 C++ 是一个糟糕的主意,他们可能有道理。但这只是一个意见;我认为使用您熟悉的 C++ 功能是有效的,而不必购买整个功能。我认为 C++ 成功的一个重要原因是它在早期就被大量程序员以这种方式使用。
Probably the best way to do this (which may or may not be possible in your case depending on your situation) is to move to C++ and use it as 'a better C'. You can use C++ without using classes, templates, operator overloading or other advanced features.
This will give you a variant of C with function overloading and default parameters (and whatever other features you chose to use). You just have to be a little disciplined if you're really serious about using only a restricted subset of C++.
A lot of people will say it's a terrible idea to use C++ in this way, and they might have a point. But's it's just an opinion; I think it's valid to use features of C++ that you're comfortable with without having to buy into the whole thing. I think a significant part of the reason for the sucess of C++ is that it got used by an awful lot of programmers in it's early days in exactly this way.
简短回答:不。
稍长回答:有一个古老的解决方法,您可以传递一个您解析的字符串 em> 用于可选参数:
其中 opt 可能包含“名称=值”对或其他内容,您可以这样称呼
它显然这只是偶尔有用。通常当您需要一个接口来实现一系列功能时。
您仍然可以在由 C++ 专业程序编写的粒子物理代码中找到这种方法(例如 ROOT)。它的主要优点是它可以几乎无限期地扩展,同时保持向后兼容性。
Short answer: No.
Slightly longer answer: There is an old, old workaround where you pass a string that you parse for optional arguments:
where opt may include "name=value" pair or something, and which you would call like
Obviously this is only occasionally useful. Generally when you want a single interface to a family of functionality.
You still find this approach in particle physics codes that are written by professional programs in c++ (like for instance ROOT). It's main advantage is that it may be extended almost indefinitely while maintaining back compatibility.
使用宏的另一个技巧:
如果仅传递一个参数,则
b
接收默认值(在本例中为 15)Another trick using macros:
If only one argument is passed,
b
receives the default value (in this case 15)还有一个选项使用
struct
:Yet another option uses
struct
s:不。
No.
不,但您可以考虑使用一组函数(或宏)来近似使用默认参数:
No, but you might consider using a set of functions (or macros) to approximate using default args:
是的,利用 C99 的功能,您可以做到这一点。这无需定义新的数据结构等即可工作,并且函数无需在运行时决定如何调用它,并且
没有任何计算开销。
有关详细说明,请参阅我的帖子
http://gustedt。 wordpress.com/2010/06/03/default-arguments-for-c99/
詹斯
Yes, with features of C99 you may do this. This works without defining new data structures or so and without the function having to decide at runtime how it was called, and
without any computational overhead.
For a detailed explanation see my post at
http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/
Jens
我改进了 Jens Gustedt 的答案,以便:
variadic.h:
简化的使用场景:
并与_Generic:
并与可变参数函数名称选择,不能与_Generic结合使用:
I improved Jens Gustedt’s answer so that:
variadic.h:
Simplified usage scenario:
And with _Generic:
And with variadic function name selection, which can't be combined with _Generic:
通常不需要,但在 gcc 中,您可以使用宏将 funcA() 的最后一个参数设置为可选。
在 funcB() 中,我使用特殊值 (-1) 来表示我需要“b”参数的默认值。
Generally no, but in gcc You may make the last parameter of funcA() optional with a macro.
In funcB() i use a special value (-1) to signal that i need the default value for the 'b' parameter.
是
通过宏
3个参数:
如果你想要第四个参数,那么需要添加一个额外的my_func3。注意 VAR_FUNC、my_func2 和 my_func 中的变化
4 参数:
唯一的例外是 float 变量不能被赋予默认值(除非它是最后一个参数,如3 个参数 case),因为它们需要句点 ('.'),而宏参数中不接受句点。但可以找出解决方法,如 my_func2 宏(4 个参数情况)
程序
输出所示:
YES
Through macros
3 Parameters:
If you want 4th argument, then an extra my_func3 needs to be added. Notice the changes in VAR_FUNC, my_func2 and my_func
4 Parameters:
Only exception that float variables cannot be given default values (unless if it is the last argument as in the 3 parameters case), because they need period ('.'), which is not accepted within macro arguments. But can figure out a work around as seen in my_func2 macro (of 4 parameters case)
Program
Output:
我偶尔会使用一个技巧,它从 C99 开始就可用,它使用可变参数宏、复合文字和指定的初始值设定项。与任何宏解决方案一样,它很麻烦,通常不推荐,除非作为最后的手段...
我的方法是按以下方式构建的:
将实际函数包装在类似函数的可变宏中:
通过使用复合文字,将传递的参数复制到临时对象中。该对象应该是直接对应于函数的预期参数列表的私有结构。示例:
这意味着初始化此结构时也使用将参数传递给函数时使用的相同类型安全(“按照分配”)规则。我们不会失去任何类型安全。同样,这会自动防止提供太多参数。
但是,上面的内容不包括空参数列表的情况。为了解决这个问题,请添加一个虚拟参数,以便初始化列表永远不为空:
类似地,我们可以计算传递的参数数量,假设传递的每个参数都可以隐式转换为
int
:#define COUNT_ARGS(...) (sizeof(int[]){0,__VA_ARGS__} / sizeof(int) - 1)
我们为默认参数定义一个宏
#define DEFAULT_ARGS (myfunc_t){0,1,2}
,其中 0 是虚拟值和 1,2 是默认值。将所有这些包装在一起,最外面的包装宏可能如下所示:
#define myfunc(...) myfunc( MYFUNC_INIT(__VA_ARGS__).x, MYFUNC_INIT(__VA_ARGS__).y )
假设内部宏
MYFUNC_INIT
返回一个myfunc_t
结构。内部宏根据参数列表的大小有条件地选择结构初始值设定项。如果参数列表很短,它将用默认参数填充。
完整示例:
输出:
Godbolt: https://godbolt.org/z/4ns1zPW16 如您所见从 -O3 反汇编来看,复合文字的开销为零。
我注意到我的方法有点让人想起当前投票最高的答案。与其他解决方案进行比较:
优点:
缺点:
int
,但情况通常并非如此。例如,严格的 C 不允许从指针到 int 的隐式转换 - 这种隐式转换是不符合标准(但流行)的编译器扩展。There's a trick I've occasionally used, which has been available since C99, using variadic macros, compound literals and designated initializers. As with any macro solution, it is cumbersome and generally not recommended other than as a last resort...
My method is built in the following way:
Wrap the actual function in a function-like, variadic macro:
By using compound literals, copy down the parameters passed into a temporary object. This object should be a private struct corresponding directly to the function's expected parameter list. Example:
This means that the same type safety ("as per assignment") rules used when passing parameters to a function is also used when initializing this struct. We don't lose any type safety. Similarly, this automatically guards against providing too many arguments.
However, the above doesn't cover the case of an empty argument list. To counter this, add a dummy argument so that the initializer list is never empty:
Similarly, we can count the number of arguments passed, assuming that every parameter passed can get implicitly converted to
int
:#define COUNT_ARGS(...) (sizeof(int[]){0,__VA_ARGS__} / sizeof(int) - 1)
We define a macro for the default arguments
#define DEFAULT_ARGS (myfunc_t){0,1,2}
, where 0 is the dummy and 1,2 are the default ones.Wrapping all of this together, the outermost wrapper macro may look like:
#define myfunc(...) myfunc( MYFUNC_INIT(__VA_ARGS__).x, MYFUNC_INIT(__VA_ARGS__).y )
This assuming that the inner macro
MYFUNC_INIT
returns amyfunc_t
struct.The inner macro conditionally picks struct initializers based on the size of the argument list. In case the argument list is short, it fills up with default arguments.
Full example:
Output:
Godbolt: https://godbolt.org/z/4ns1zPW16 As you can see from the -O3 disassembly, there is zero overhead from the compound literals.
I noticed that my method reminds a bit of the current, top-voted answer. For comparison with other solutions here:
Pros:
Cons:
int
, which often isn't the case. For example strict C does not allow implicit conversions from pointers toint
- such implicit conversions is a non-conforming (but popular) compiler extension.是的,你可以做一些模拟的事情,在这里你必须知道你可以获得的不同参数列表,但你有相同的函数来处理所有这些。
Yes you can do somthing simulair, here you have to know the different argument lists you can get but you have the same function to handle then all.
您不需要仅将 VARARGS 与 C 一起使用。这是一个示例。
这个答案与上面的两个函数方法非常相似,但在这种情况下,您使用宏作为定义参数的函数名称。
you don't need to use VARARGS with just C. Here is an example.
This answer is very similar to the two functions method above but in this case, you're using a macro for the function name that defines the arguments.
https://github.com/cindRoberta/C/blob/主控/结构/函数/default_parameter.c
https://github.com/cindRoberta/C/blob/master/structure/function/default_parameter.c
我知道如何以更好的方式做到这一点。
您只需将 NULL 分配给参数,因此,您将没有任何值。然后检查参数值是否为
NULL
,将其更改为默认值。不过,它会引起警告。更好的选择是分配一个值,如果参数值是这样的话,则该值不会执行任何操作:
在上面的示例中,如果
x
是1
函数会将其更改为2
;感谢@user904963,编辑:
如果您必须涵盖所有数字范围,那么添加另一个参数只是为了告诉函数是否将参数设置为默认值并不难。
但是,请记住包含
stdbool.h
I know how to do this in a better manner.
You simply assign NULL to a parameter, so, you will have no value. Then you check if the parameter value is
NULL
, you change it to the default value.Though, it will cause warnings. a better choice would be to assign a value that will do nothing if the parameter value is that:
In the example above, if
x
is1
the function changes it to2
;Thanks to @user904963, EDIT:
if you have to cover all ranges of numbers, it's not hard to add another argument only to say to the function whether it would set the parameter to default or not
However, remember to include
stdbool.h
我用bk适当地做了它。和埃里克。
必须在#define(可变参数宏)中更改默认值
I made it appropriately by bk. and Eric.
The default value must be changed in #define (variadic macros)
为什么我们不能这样做。
为可选参数指定默认值。这样,函数的调用者不一定需要传递参数的值。该参数采用默认值。
并且很容易,这个论点对于客户来说就变成了可选的。
例如
void foo(int a, int b = 0);
这里 b 是一个可选参数。
Why can't we do this.
Give the optional argument a default value. In that way, the caller of the function don't necessarily need to pass the value of the argument. The argument takes the default value.
And easily that argument becomes optional for the client.
For e.g.
void foo(int a, int b = 0);
Here b is an optional argument.