在 Python 中,我习惯了这样的事情
def send_command(command, modifier = None):
然后修饰符参数是可选的,没有该参数可以与参数为 0 区分开来。C 中有类似的功能吗? 我对 C 和 Google 没有经验,但找不到如何在 C 中使用可选参数的明确说明。看来你可以类似地分配它们,如下所示:
void send_command(uint8_t command, uint8_t modifier = 0) {
那么第二个参数是可选的,如果不使用则默认为 0? (编辑:不,这无论如何都是无效的C)
但是该函数可以区分
send_command(SOMETHING)
和 send_command(SOMETHING, 0)
吗? 理想情况下,第二个参数可以是任何 uint8 值,包括 0。
也许 NULL 与 0 不同?
void send_command(uint8_t command, uint8_t modifier = NULL) {
C 不支持可选参数。它也不支持函数重载,而函数重载通常可以达到类似的效果。
C99 中可以使用可变参数宏使用可选参数:
#define JUST3(a, b, c, ...) (a), (b), (c)
#define FUNC(...) func(JUST3(__VA_ARGS__, 0, 0))
现在
FUNC(x)
扩展为 func((x), (0), (0))
,FUNC(x,y)
扩展为 func((x), (y), (0))
,等等
正如其他人所说,C 不直接支持函数的默认参数。但有一些方法可以使用宏来做到这一点。 P99 有方便的“元”宏,使此功能相对容易指定。作为避免重复指定
pthread_mutex_init
函数的第二个参数的示例:
P99_PROTOTYPE(int, pthread_mutex_init, pthread_mutex_t*, pthread_mutexattr_t const*);
#define pthread_mutex_init(...) P99_CALL_DEFARG(pthread_mutex_init, 2, __VA_ARGS__)
P99_DECLARE_DEFARG(pthread_mutex_init, , (pthread_mutexattr_t*)0);
之后直接使用
pthread_mutex_init(&my_mutex);
这里默认参数求值的语义与C++相同,即默认参数的求值上下文是声明的上下文。还可以通过求值上下文是宏调用上下文的方式来指定这一点。
C 编程语言没有可选参数。 C++ 可以,但“许多现代编程语言之母”C 却没有......
通过使用结构体,C 中可以有可选参数,甚至是带标签的参数:
typedef struct {
int a, b, c;
} Options;
void func(Options options);
然后,像这样调用
func
(自 C99 起):
func((Options){ 1, 2 });
func((Options){ .c = 3 });
未指定的值默认为零。
如果你可以使用宏,你可以写:
#define func(...) func((Options){ __VA_ARGS__ })
这样你就可以这样打电话:
func(1, 2);
func(.c = 3);
您甚至可以指定零以外的值(这与 C++ 不兼容):
struct options {
char unused;
int a, b, c;
};
void func(struct options options);
#define func(...) func((struct options){ .a = 1, 2, 3, .unused = 0, __VA_ARGS__ })
好吧,这变得相当难看。
还要记住,传递结构体作为参数会使程序变慢(因为结构体存储在内存中,而简单值(例如整数和指针)存储在寄存器中),因此这些结构体解决方案当然不应该用于低级函数需要性能。
我经常使用结构体来提供可选的、默认为空的参数。我尝试使用我的宏想法,但它似乎从来都不是一个好主意。
我不明白为什么其他人没有像我一样花这么多时间思考结构......!
让我们继续讨论丑陋的代码。有时我使用这个技巧(从 C99 开始也有效):
void func(int a, int b, int c);
#define func(a, ...) func(a, (int[2]){ __VA_ARGS__ }[0], (int[2]){ __VA_ARGS__ }[1])
然后您可以使用 1、2 或 3 个参数调用
func
,如果未指定,b
和 c
默认为零。
请注意,编译器优化将消除数组。