为什么这种在 C 中进行函数重载的方法有效? [英] Why this method for function overloading in C works?
问题描述
我已经查看了一些在 C 中执行此操作的方法,但我只找到了 C99.
I've looked over some ways of doing it in C but i've only found for C99.
但我遇到了以下解决方案,取自 Lock Less.
But i've come across the solution below, taken from Lock Less.
问题是,我不太明白它是如何工作的,我想知道那里发生的事情的基本原理,以便能够更清楚地理解它.
The thing is, I don't quite understand how it works and would like know the fundamentals of what is going on there to be able to understand it more clearly.
我在网上找了一段时间,发现了这个 关于__VA_ARGS__,但不幸的是,仅此还不够.
I've fetched the web for a while and found this about __VA_ARGS__, but that alone wasn't enough unfortunately.
我非常感谢有关此事的解释或指导,任何类型的参考都会有所帮助.
I would really appreciate an explanation or some guidance about this matter, any kind of reference would help.
我使用带有 -ansi 标志的 GCC-5.4.1 编译了这段代码.
I've compiled this code with GCC-5.4.1 with -ansi flag.
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#define COUNT_PARMS2(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _, ...) _
#define COUNT_PARMS(...)\
COUNT_PARMS2(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
void count_overload1(int p1)
{
printf("One param: %d\n", p1);
}
void count_overload2(double *p1, const char *p2)
{
printf("Two params: %p (%f) %s\n", p1, *p1, p2);
}
void count_overload3(int p1, int p2, int p3)
{
printf("Three params: %c %d %d\n", p1, p2, p3);
}
void count_overload_aux(int count, ...)
{
va_list v;
va_start(v, count);
switch(count)
{
case 1:
{
int p1 = va_arg(v, int);
count_overload1(p1);
break;
}
case 2:
{
double *p1 = va_arg(v, double *);
const char *p2 = va_arg(v, const char *);
count_overload2(p1, p2);
break;
}
case 3:
{
int p1 = va_arg(v, int);
int p2 = va_arg(v, int);
int p3 = va_arg(v, int);
count_overload3(p1, p2, p3);
break;
}
default:
{
va_end(v);
printf("Invalid arguments to function 'count_overload()'");
exit(1);
}
}
va_end(v);
}
#define count_overload(...)\
count_overload_aux(COUNT_PARMS(__VA_ARGS__), __VA_ARGS__)
int main(int argc, char const *argv[])
{
double d = 3.14;
count_overload(1);
count_overload(&d, "test");
count_overload('a',2,3);
return 0;
}
输出为:
One param: 1
Two params: 0x7ffc0fbcdd30 (3.140000) test
Three params: a 2 3
推荐答案
让我们分解 COUNT_PARMS
和 COUNT_PARMS2
宏.第一个 COUNT_PARMS
:
Let's break down the COUNT_PARMS
and COUNT_PARMS2
macros. First COUNT_PARMS
:
#define COUNT_PARMS(...)\
COUNT_PARMS2(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
由于宏不包含命名参数,传递给它的任何参数都被放置在 __VA_ARGS__
的位置.
Since the macro contains no named arguments, any parameters passsed to it are put in place of __VA_ARGS__
.
所以以下调用:
COUNT_PARMS(arg1)
COUNT_PARMS(arg1, arg2)
COUNT_PARMS(arg1, arg2, ,arg3)
将扩展到:
COUNT_PARMS2(arg1, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
COUNT_PARMS2(arg1, arg2, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
COUNT_PARMS2(arg1, arg2, arg3, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
// x
我将参数隔开,以便您可以看到哪些参数彼此对应.请特别注意标记为 x
的列.这是传递给 COUNT_PARMS
的参数数量,它是每种情况下的第 11 个参数.
I spaced out the arguments so you can see which ones correspond to each other. Make special note of the column marked x
. This is the number of parameters passed to COUNT_PARMS
, and it's the 11th argument in each case.
现在让我们看看COUNT_PARMS2
:
#define COUNT_PARMS2(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _, ...) _
有 11 个名称参数,加上 ...
以说明任何其他参数.宏的整个主体是 _
,即第 11 个参数的名称.所以这个宏的目的是取 11 个或更多的参数,并用第 11 个参数替换它们.
There are 11 names arguments, plus ...
to account for any additional arguments. The entire body of the macro is _
, which is the name of the 11th argument. So the purpose of this macro is to take 11 or more arguments and replace them with just the 11th argument.
再看COUNT_PARAMS
的定义,它以这样一种方式扩展,它调用COUNT_PARMS2
,第11个参数是传递给COUNT_PARAMS的参数个数代码>.魔法就是这样发生的.
Looking again at the definition of COUNT_PARAMS
, it expands in such a way that it calls COUNT_PARMS2
with the 11th parameter being the number of parameters passed to COUNT_PARAMS
. This is how the magic happens.
现在查看main
中的函数调用:
Now looking at the function calls in main
:
count_overload(1);
count_overload(&d, "test");
count_overload('a',2,3);
这些扩展为:
count_overload_aux(COUNT_PARMS(1), 1);
count_overload_aux(COUNT_PARMS(&d, "test"), &d, "test");
count_overload_aux(COUNT_PARMS('a',2,3), 'a',2,3);
那么:
count_overload_aux(COUNT_PARMS2(1, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1), 1);
count_overload_aux(COUNT_PARMS2(&d, "test", 10, 9, 8, 7, 6, 5, 4, 3, 2, 1), &d, "test");
count_overload_aux(COUNT_PARMS2('a',2,3, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1), 'a',2,3);
那么:
count_overload_aux(1, 1);
count_overload_aux(2, &d, "test");
count_overload_aux(3, 'a',2,3);
最终结果是您可以调用一个接受可变数量参数的函数,而无需明确说明有多少.
The end result is that you can call a function that takes a variable number of arguments without having to explicitly say how many there are.
这篇关于为什么这种在 C 中进行函数重载的方法有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!