2

在我的代码中,我必须使用几个函数作为lambdas,例如您应该提供的 to qsort
因此,当我传递 type 的函数时int,程序运行良好。但是当我还添加了另一个 type 函数时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 个字节,所以它必须是指针而不是双精度。这就是我收到该错误消息的原因。
我去维基百科找了个例子,发现了额外的(). 我已经添加了它们,现在它返回 8 个字节并且工作正常。

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

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

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

4

3 回答 3

2

在这个表达式中:

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

另外,请参阅此答案以获取详细信息以及此有趣的答案。

于 2012-11-28T20:59:40.023 回答
2

你的问题来自于:

double *getter(struct human*)

隐式转换为:

double *(*getter)(struct human*)

这就是为什么你会出错,因为你无法比较(double *)double

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

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

double (*getter)(struct human*)  /* 'getter' is a pointer to function taking
                                    struct human and returning double */
于 2012-11-28T20:32:58.960 回答
0

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

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

其中比较器包括:

return getter(h) < val;

或类似的东西。

这里的关键是 getter 的结果被 operator 使用<。另一方面,比较器的结果被转换为布尔值(嗯,不是真的:这是 C。但这是相同的想法。)您可以将任何指针隐式转换为布尔值(即整数),没有提出任何警告。

所以会发生什么:

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

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

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

所以没有错误。

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

于 2012-11-28T20:30:44.697 回答