调用带有额外参数的C函数是否可移植?

调用带有额外参数的C函数是否可移植?,c,C,考虑以下代码: #include <stdio.h> typedef int (*addif_fn_t) (int, int, int); int add (int a, int b) { return a + b; } int addif (int a, int b, int cond) { return cond ? (a + b) : 0; } int main() { addif_fn_t fn; fn = addif; pr

考虑以下代码:

#include <stdio.h>

typedef int (*addif_fn_t) (int, int, int);

int add (int a, int b) {
    return a + b;
}

int addif (int a, int b, int cond) {
    return cond ? (a + b) : 0;
}

int main() {
    addif_fn_t fn;

    fn = addif;
    printf("addif:\t%d %d\n", fn(1, 2, 1), fn(1, 2, 0));

    fn = (addif_fn_t)add;
    printf("add:\t%d %d\n", fn(1, 2, 1), fn(1, 2, 0));

    return 0;
}
问题是:这个成语的可移植性如何?C是否允许调用参数超过其接受范围的函数


我的猜测是,它完全取决于ABI以及它如何确定函数参数和局部变量存储在哪里。更重要的是,这可能不是可移植代码。但是我已经在实际的代码库中见过多次使用这个习惯用法。

作为一个实际问题,我不知道它有多“可移植”(在现有实现下,或者至少在您关心的实现子集下,它是否会像您所期望的那样工作)

就C标准而言,它根本不可移植。程序具有未定义的行为,因为它通过类型(
int(*)(int,int)
的表达式调用函数,该类型与函数的实际类型(
int(*)(int,int,int)
)不同。(前者是用于定义
add
函数的类型;后者是用作调用前缀的表达式
fn
的类型。)

第6.5.2.2节第9段对此进行了说明:

如果函数定义的类型与 类型(表达式的类型),由表示 调用函数时,行为未定义

(该链接指向C11标准N1570草案的PDF。在该标准的其他版本中,您会发现类似或可能相同的措辞。)

我的建议是:不要那样做

但是,请注意,变量函数(如用
,…
声明的
printf()
函数)的多余参数会被悄悄地忽略。例如,这是完全合法的:

printf("Ignore the arguments\n", 10, 20, 30);
如果您确实需要能够在不知道需要多少参数的情况下调用函数,这可能是一种可行的方法(尽管您将丢失对任何匹配
,…
的参数的编译时类型检查)


对于非变量函数,您可以自由地将函数指针从一种类型转换为另一种类型,但每次调用都必须转换回正确的类型。

相关:在C中,
int main()
可以接受任意数量的参数。而
int main(void)
不能接受任何参数。很可能参数从右到左插入堆栈,调用方会清理堆栈。这就是它工作的原因。但是它取决于调用约定,所以我不会称它为可移植的。@PengZhang:这是不正确的。
main()
是一个特例。
printf("Ignore the arguments\n", 10, 20, 30);