我99%在确认C标准和几个comp.lang.c帖子后确信这是合法的,但我希望有人可以在标准中提供准确的语言,允许(或禁止)这种情况:< / p>
#include <stdio.h>
double id (double x) { return x; }
double add2 (double x, double y) { return x + y; }
double add3 (double x, double y, double z) { return x + y + z; }
typedef double (*fp) ();
static fp funcs[] = { id, add2, add3 };
int main (void)
{
printf("id(5.3) = %f\n", funcs[0](5.3));
printf("add2(5.3, 6.1) = %f\n", funcs[1](5.3, 6.1));
printf("add3(5.3, 6.1, 7.2) = %f\n", funcs[2](5.3, 6.1, 7.2));
return 0;
}
提供的示例使用-Wall -pedantic -ansi
在MinGW gcc 4.4.0下为我提供了预期的结果。
考虑:
float
double
参数隐式地提升积分参数。通过函数指针调用未指定参数的函数时,此行为是否会以任何方式更改? (我不明白为什么会这样。)...
说明符的函数(例如double uhoh (double x, ...)
)。从实现的角度来看,这是有道理的,但我无法确定禁止此条款的标准中的条款。答案 0 :(得分:3)
首先我可以建议标准函数调用语法:
void foo(int);
foo(3);
是根据foo
衰减到函数指针,然后被调用来定义的;因此,我不明白为什么你的情况和“标准”函数调用之间会有任何区别。
其次,n1256 6.5.2.2详细说明了函数调用语义,对于没有原型的函数指针来说似乎很好定义了参数的数量和类型与参数的数量和类型相匹配。
根据n1256 6.7.5.3p15,空参数列表与可变参数列表不兼容:
如果一种类型具有参数类型列表 另一种类型由a指定 函数声明符不是其中的一部分 一个函数定义和那个 包含一个空的标识符列表, 参数列表不得有 省略号终结符和类型 每个参数都应兼容 与由此产生的类型 应用默认参数 促销。
这意味着将一个变量函数指针指向一个没有原型的函数指针是一个约束违规(6.5.16.1p1),因为你要指定不兼容类型的指针。
我猜想将非可编程函数指针转换为非原型函数指针也是UB,可能是CV;但我没有检查过。
答案 1 :(得分:2)
你是正确的,这个程序有完全明确定义的行为,只要你打电话时的参数的数量和类型与被调用的函数定义中的那些相匹配。见6.5.2.2第6段。我的相关问题也可能是有意义的:
Is this dubious use of a non-prototype function declaration valid?
答案 2 :(得分:1)
只要所有参数类型都提升为自身并且所有提供的参数都是正确的类型,代码就是定义良好的。
如果你想恢复一些类型安全措施,你可以使用显式的强制转换或联合,例如
#include <stdio.h>
static double id(double x) { return x; }
static double add2(double x, double y) { return x + y; }
static double add3(double x, double y, double z) { return x + y + z; }
union func
{
double (*as_unary)(double x);
double (*as_binary)(double x, double y);
double (*as_ternary)(double x, double y, double z);
};
static const union func funcs[] = {
{ .as_unary = id },
{ .as_binary = add2 },
{ .as_ternary = add3 }
};
int main(void)
{
printf("id(5.3) = %f\n", funcs[0].as_unary(5.3));
printf("add2(5.3, 6.1) = %f\n", funcs[1].as_binary(5.3, 6.1));
printf("add3(5.3, 6.1, 7.2) = %f\n", funcs[2].as_ternary(5.3, 6.1, 7.2));
return 0;
}