解释这个gcc函数的典型行为

时间:2012-11-28 19:50:18

标签: c types syntax function-pointers

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

  

1.c:44:29:错误:无效操作数到二进制< (有'double *'和'double')

从这一行:

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个,所以它必须是指针而不是double。这就是我收到错误信息的原因 我前往Wikipedia作为示例,发现了其他()。我添加了它们,现在它返回8个字节并且工作正常。

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

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

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

3 个答案:

答案 0 :(得分: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 */

答案 1 :(得分:2)

在这个表达式中:

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

... getter具有函数类型(函数类型返回指向double的指针)。在此:

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

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

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

  

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

所以,你的表达:

return (*getter)(a) < target;

...根据标准将getter从函数类型衰减到函数指针类型(类型double * (*)(struct human*)),尽管您需要double (*)(struct human*)

一旦您将函数传递给somefunction,您就会收到警告,它们是不兼容的类型,例如:

  

警告:从不兼容的指针类型

传递'som​​efunction'的参数2

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

答案 2 :(得分:0)

您没有提供所有代码,因此我只是猜测您正在执行以下操作:

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

比较器包括:

return getter(h) < val;

或类似的东西。

这里的关键是运算符<使用getter的结果。另一方面,比较器的结果是转换为布尔(好吧,不是真的:这是C.但它是同样的想法。)并且你可以隐式地将任何指针转换为布尔值(这是一个整数),没有提出任何警告。

所以会发生什么:

  1. 比较器返回int,但

  2. 来电者期待int*。不过那没关系;指针和整数以同样的方式返回。

  3. 调用者现在想要使用int*,就好像它是int一样,这也没关系。

  4. 所以没有错误。

    此外,返回值的零度由意外演员和隐式转换保留,所以作为奖励,你得到正确的答案。