为什么这种在 C 中进行函数重载的方法有效? [英] Why this method for function overloading in C works?

查看:60
本文介绍了为什么这种在 C 中进行函数重载的方法有效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经查看了一些在 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_PARMSCOUNT_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆