在 C [duplicate] 中使用带有空参数列表的函数指针

Using function pointers with empty parameter lists in C [duplicate]

提问人:talentless 提问时间:5/26/2023 最后编辑:talentless 更新时间:6/11/2023 访问量:120

问:

我见过很多 C 代码使用指向具有空参数列表的函数的指针,以便它们可用于调用具有不同原型的函数而无需强制转换,只要返回类型相同。

例如:

#include <stdio.h>

typedef void (*func_returning_void) ();

void empty_args ()
{
    printf("empty args\n");
}

void zero_args (void)
{
    printf("zero args\n");
}

void one_int_arg (int arg)
{
    printf("one arg: %d\n", arg);
}

void two_string_args (const char *arg1, const char *arg2)
{
    printf("two args: %s %s\n", arg1, arg2);
}

int main (void)
{
    func_returning_void funcptr;

    funcptr = empty_args;
    funcptr();
    funcptr = zero_args;
    funcptr();
    funcptr = one_int_arg;
    funcptr(1);
    funcptr = two_string_args;
    funcptr("one", "two");
}

只要参数的数量和类型与被调用函数的参数列表匹配,这种技术是定义明确的,还是依赖于未定义的行为?

注意:我知道反之则是未定义的行为,因为在函数定义中,空参数列表与恰好为零的参数具有相同的含义;正如 C 标准所述:()(void)

“函数声明符中的空列表是该函数定义的一部分,它指定该函数没有参数。”

void empty_params() {}

int main (void)
{
    void (*funcptr) (int) = empty_params; // UB
    funcptr(1234);
}
C 参数传递 指针 函数 原型

评论

1赞 Ted Lyngmo 5/26/2023
空参数列表与 (pre C23) 不同。如果是,您的程序将无法编译。在 C23 中,是的,那么它是一样的,所以你的示例程序在 C23 中不起作用。void
1赞 Harith 5/26/2023
空参数列表表示该函数采用未指定的参数数量和类型。它与 的含义不同(void)
0赞 Harith 5/26/2023
旁白:你也测试过可变参数函数吗?
0赞 talentless 5/26/2023
但该标准说:“作为该函数定义一部分的函数声明器中的空列表指定该函数没有参数。

答:

3赞 Eric Postpischil 5/26/2023 #1

2018 年标准中适用的段落是 6.5.2.2 6,因为它以“如果表示被调用函数的表达式具有不包含原型的类型”开头。(原型是函数的声明,用于声明其参数的类型。所以不包括原型。预计这将在 2023 年标准中发生变化,该标准取消了对没有原型的函数声明的支持。 因为函数声明将变得与 相同。typedef void (*func_returning_void) ();()(void)

关于调用用原型定义的函数,这一段说:

...对每个参数执行整数升级,并且具有 type 的参数将提升为 。这些称为默认参数升级。如果参数数不等于参数数,则行为未定义。如果函数是使用包含原型的类型定义的,并且原型以省略号 () 结尾,或者升级后的参数类型与参数的类型不兼容,则行为是未定义的...floatdouble, ...

因此,当使用声明 with 的函数指针调用用原型定义的函数时,只要参数数与参数数匹配,参数提升后的类型兼容,并且定义不使用省略号,就可以定义行为。()

请注意,示例的行为不是由 C 标准定义的。 使用 type 的参数调用函数,而函数使用 type 的参数定义,这些参数是不兼容的类型。two_strings_argsfuncptr("one", "two");char *const char *