【问题标题】:Is it possible to have variable inputs in C functionsC函数中是否可以有变量输入
【发布时间】:2014-12-16 05:45:00
【问题描述】:

我正在制作一个简单的函数来计算两个输入之间的差异。真的只是为了方便。个人头文件中可以参考的东西。

我希望输入:

两个整数:输出一个整数

两个双打:输出一个双打

我尝试在网上搜索某种全局输入声明,但找不到。

我不喜欢有两个功能,只有一个简单的。

示例代码头: int diff(int a,int b); 双差异(双a,双b);

感谢您的帮助!

【问题讨论】:

  • 添加第三个参数,指示参数和输出的类型。然后让代码检查第三个参数并采取相应措施。

标签: c function int double


【解决方案1】:

不,这称为重载,它不是 C 的功能。你最好创建 distinct 函数来处理这个问题。

可以用各种 C 魔法来完成(你几乎可以用足够的 C 魔法来做任何事情),但是生成的代码可能太丑了,以至于无法维护:-)

例如,C11 引入了泛型选择,带有 _Generic 主表达式,这允许您根据输入参数类型调用不同的函数。实际上,它的作用远不止于此,但根据您的问题,这是您感兴趣的方面。

例如,假设您这样定义了两个函数:

int     diffi (int    a, int    b) { return a - b; }
double  diffd (double a, double b) { return a - b; }

通常,必须根据您的输入类型来决定调用哪个。 C11 通用选择功能允许您这样做:

#define diff(a,b)        \
    _Generic((a),        \
        double:  diffd,  \
        int:     diffi,  \
        default: diffX   \
    )(a,b)

这基本上是在源代码中找到宏diff(x,y)

  • 确定表达式(a) 的类型,而不对其求值;
  • 将与该类型匹配的令牌注入源流(如果未找到匹配则默认);
  • 在源流末尾注入(a,b) 文本。

所以,如果您的源文件包含以下行:

x = diff (1,   2);
y = diff (1.0, 2);

这将被翻译成:

x = diffi (1  , 2);
y = diffd (1.0, 2);

为您提供有效的超载。

现在这是一个比较简单的案例,因为它仅依赖于第一个参数类型 - 如果你尝试这样做,你会看到一个漏洞:

z = diff (1, 2.0);

因为 first 参数的类型是 int,所以你会得到:

z = diffi (1, 2.0);

这不是你真正想要做的。这就是复杂性所在,因为您必须涵盖 四种 可能性:{int/int, int/double, double/int, double/double} 并且根据参数的数量和每个参数的可能类型,它会变得更多复杂.

但是,您的完整案例可以通过明智地使用默认值和嵌套的通用选择来完成,例如:

#define diff(a,b)              \
    _Generic((a),              \
        double:  diffd,        \
        default: _Generic((b), \
            double:  diffd,    \
            default: diffi     \
        )                      \
    )(a,b)

这可以读作:

  • 如果a的类型为double,则使用diffd
  • 否则,如果b的类型为double,则使用diffd
  • 否则,请使用diffi
  • 别忘了也注入参数。

以下完整程序(使用clang 3.0 编译)展示了此功能的实际应用:

#include <stdio.h>

int diffi (int a, int b) {
    printf ("diffi %d %d", a, b);
    return a - b;
}
double diffd (double a, double b) {
    printf ("diffd %f %f", a, b);
    return a - b;
}

#define diff(a,b)              \
    _Generic((a),              \
        double:  diffd,        \
        default: _Generic((b), \
            double:  diffd,    \
            default: diffi     \
        )                      \
    )(a,b)

int main (void) {
    int i; double d;
    i = diff (1  , 2  ); printf (" --> %d\n", i);
    d = diff (1.0, 2  ); printf (" --> %f\n", d);
    d = diff (1  , 2.0); printf (" --> %f\n", d);
    d = diff (1.0, 2.0); printf (" --> %f\n", d);
    return 0;
}

该程序的输出是:

diffi 1 2 --> -1
diffd 1.000000 2.000000 --> -1.000000
diffd 1.000000 2.000000 --> -1.000000
diffd 1.000000 2.000000 --> -1.000000

表明针对四种可能性调用了正确的函数。


事实上,正如rici 在评论中指出的那样,您可以依赖 C 的提升规则,其中添加 doubleint(以任何顺序)会给您一个 double 而添加两个int 变量会给你一个int

#define diff(a,b) _Generic((a+b), double:diffd, default:diffi)(a,b)

【讨论】:

  • C11 功能_Generic 怎么样? (参见open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 的第 6.5.1.1 节)它不如 C++ 漂亮,但也没有那么丑。
  • @rici,您应该尝试使用一个四参数函​​数,每个函数都可以是三种类型之一,然后您会欣赏它的丑陋 :-) 但是,它适用于较小的用例所以我会把它作为一个选项添加。
  • @paxdiablo:我自己使用 C++ :-) 但是 _Generic 确实足以解决这个问题。
  • @rici,你去吧,你是对的,它并不像我最初想象的那么难看(至少对于特定的用例)。
  • @rici,我并不经常对某人的鬼鬼祟祟印象深刻 - 好电话:-)
【解决方案2】:

Function overloading 在 C 中不可用。 一些可能的解决方法

  1. 为 ex 使用两个具有不同名称的函数:diff_i 和 diff_d (推荐)
  2. 使用varargs(不推荐)这将使代码难以随着时间的推移而维护。
  3. 使用_Generic

【讨论】:

    【解决方案3】:

    IEEE754 double 的精度超过 32 位,因此只需编写 double 版本,让自动转换处理其余部分。

    当然,如果您使用的系统 sizeof(int)&gt;4char 超过 8 位,最好为每种类型编写变体,并为它们采用某种匈牙利命名约定.然后你可以写,也许:

    int diffi(int, int);
    double diffd(double, double);
    ssize_t diffz(size_t, size_t);
    

    等等。本质上,这是手动 name-mangling,C++ 编译器使用相同的技术为目标文件的导出表生成不同的符号名。

    【讨论】:

    • A C int 有一个最小 范围,而不是最大范围。所以很可能有一些实现,int 需要的精度比double 的精度要高 :-) 话虽如此,但如果你知道这些限制,这不是一个坏主意。
    • 是的。谢谢!这给了我一些补充答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-23
    • 2014-01-02
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    相关资源
    最近更新 更多