【问题标题】:Explain this gcc functions' typization behaviour解释这个 gcc 函数的类型化行为
【发布时间】:2012-11-16 18:53:33
【问题描述】:

在我的代码中,我必须使用几个函数作为 lambdas,例如您应该提供给qsort
因此,当我传递int 类型的函数时,程序运行良好。但是当我还添加了double 类型的另一个函数时,出现了错误消息:

1.c:44:29: 错误:二进制

从行:

return (*getter)(a) < target

getter 是指向的指针:

double get_sex(struct human* a) { // it's the second function I've passed
    return a->sex;
}

我传递的两个函数之间的唯一区别是第一个是int,第二个是double

sometype somefunction (some parameters,
        int *comparator(struct human*, double, double *(struct human*)),
        double *getter(struct human*) ) {
    ....
}

我开始使用sizeof 对其进行检查,发现代码(*getter)(*a) 以某种方式返回4 个字节而不是8 个字节,因此它必须是一个指针而不是双精度。这就是我收到该错误消息的原因。
我以Wikipedia 为例,发现了额外的()。我已经添加了它们,现在它返回 8 个字节并且工作正常。

        double (*getter)(struct human*) ) {

所以问题是:为什么要在getter 周围加上括号,而不是在comparator 周围加括号?函数返回double而不是int的原因是什么?!
这是我从未听说过的语法细节。

(我使用在我的 Windows 上已经安装的编译器 - 来自 Perl 解释器 Strawberry)

【问题讨论】:

  • 您应该发布一个小而完整的示例来说明问题。答案可能取决于一个小细节。

标签: c types syntax function-pointers


【解决方案1】:

您没有提供所有代码,所以我只是猜测您正在做类似的事情:

if (comparator(h, val, getter)) { ... }

其中比较器包括:

return getter(h) < val;

或类似的东西。

这里的关键是getter的结果被操作符&lt;使用。另一方面,比较器的结果转换为布尔值(嗯,不是真的:这是 C。但它是相同的想法。)您可以将任何指针隐式转换为布尔值 (即一个整数),不会引发任何警告。

那么会发生什么:

  1. 比较器返回一个int,但是

  2. 调用者期待int*。不过没关系;指针和整数的返回方式相同。

  3. 调用者现在想像使用int 一样使用int*,这也可以。

所以没有错误。

此外,意外转换和隐式转换保留了返回值的零性,因此作为奖励,您会得到正确的答案。

【讨论】:

    【解决方案2】:

    你的问题来自于:

    double *getter(struct human*)
    

    隐式转换为:

    double *(*getter)(struct human*)
    

    这就是你得到错误的原因,因为你无法比较 (double *)double

    int 没有问题,因为你的指针 (int *) 被转换为 int 并且可以进行比较。但是,您的编译器应该警告您从指针到整数的隐式转换。

    这里的问题是我从来没有见过你可以用这种方式声明一个函数指针参数。我试图写一段代码,显然它有效。但是,这可能是 GCC 的一些非标准行为。定义函数指针的正确方法是使用括号。即

    double (*getter)(struct human*)  /* 'getter' is a pointer to function taking
                                        struct human and returning double */
    

    【讨论】:

      【解决方案3】:

      在这个表达式中:

      int myfunc( double *getter(struct human*) );
      

      ...getter 具有 函数类型(函数类型返回指向双精度的指针)。在此期间:

      int myfunc( double (*getter)(struct human*) );
      

      ...它有函数指针类型(指向返回双精度的函数类型的指针)。

      函数类型和函数指针类型本质上以相同的方式工作,因为在大多数情况下,函数类型几乎立即衰减为函数指针类型。我相信这就是标准在这里所说的:(C99,6.3.2.1/4):

      函数指示符是具有函数类型的表达式。除了 当它是 sizeof 运算符或一元 & 的操作数时 运算符,类型为“函数返回类型”的函数指示符 转换为类型为“指针”的表达式 函数返回类型''。

      那么,你的表情:

      return (*getter)(a) < target;
      

      ...按照标准,getter 从函数类型衰减为函数指针类型(double * (*)(struct human*) 类型),尽管您想要 double (*)(struct human*)

      当您将函数传递给somefunction 后,您应该会收到警告,指出它们的类型不兼容,例如:

      警告:从不兼容的指针类型传递“somefunction”的参数 2

      另外,请参阅answer for detailsas well as this interesting one

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-11
        相关资源
        最近更新 更多