Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 对其他函数使用void(*)指针_C_Function_Pointers_Language Lawyer - Fatal编程技术网

C 对其他函数使用void(*)指针

C 对其他函数使用void(*)指针,c,function,pointers,language-lawyer,C,Function,Pointers,Language Lawyer,通过void(*f)(指针访问中具有不同参数列表的函数的指针是否合法?下面的程序使用gcc编译时没有警告,看起来运行正常,但它是否合法 #include <stdio.h> #include <stdlib.h> typedef void funp(); static void funcall( funp* F, int args, double x) { switch( args) { case 0:

通过
void(*f)(
指针访问中具有不同参数列表的函数的指针是否合法?下面的程序使用gcc编译时没有警告,看起来运行正常,但它是否合法

#include    <stdio.h>
#include    <stdlib.h>

typedef void    funp();

static  void    funcall( funp* F, int args, double x)
{
    switch( args)
    {
        case    0:  F();    break;
        case    1:  F(x);   break;
    }
}

static  void    fun0( void)
{
    printf( "zero\n");
}

static  void    fun1( double x)
{
    printf( "one\t%f\n", x);
}

int main( )
{
    funcall( (funp*)fun0, 0, 17.0);
    funcall( (funp*)fun1, 1, 17.0);
    return EXIT_SUCCESS;
}

如果
nargs
参数与函数所使用的参数数量不匹配,这将是未定义的行为,但是如果存在匹配,是否合法?

在这种特殊情况下,调用是合法的

本手册第6.7.6.3p15节详细说明了如何使两种功能类型兼容(相关部分以粗体显示):

对于要兼容的两种功能类型,两者均应规定 兼容的返回类型。此外,如果需要,参数类型将列出 两者均存在,应在参数数量和 使用省略号终止符;相应参数 应具有兼容类型如果一种类型具有参数类型列表 另一种类型由函数声明器指定 不是函数定义的一部分,并且包含空 标识符列表,参数列表不应有省略号 终端和每个参数的类型应与 应用默认值产生的类型 参数升级。如果一种类型具有参数类型列表和 其他类型由包含 (可能为空)标识符列表,两者的编号应一致 参数的类型,以及每个原型参数的类型 与应用程序生成的类型兼容 将默认参数升级为 对应的标识符。(在确定类型时) 复合类型的兼容性和可用性,每个参数都已声明 带函数或数组类型被视为具有调整后的类型 并且使用限定类型声明的每个参数都被视为具有 其声明类型的非限定版本。)

因此,您有一个类型为的
typedef

void()
void(void)
void(double)
和具有以下类型的函数:

void()
void(void)
void(double)
这两个函数定义不使用省略号(
),因此满足第一个条件。对于第二个条件,让我们看看默认参数提升是什么。这些在第6.5.2.2p6节中规定:

如果表示被调用函数的表达式具有 不包括原型的类型,整数 对每个参数和具有类型的参数执行
float
升级为
double
。这些被称为默认值 辩论升级

第一个函数没有参数,因此是兼容的。第二个函数有一个单
double
参数,它与默认参数匹配,因此也是兼容的

为了给出更多示例,以下功能也将兼容:

void f1(long);
void f2(int);
但这些都不会:

void f3(float);
void f4(char);
void f5(short);

另一个答案是,您显示的代码今天是有效的C。但由于使用了没有参数列表的函数类型,这种情况在将来的任何时候都可能发生变化

6.11未来语言方向 6.11.6函数声明器 使用带空括号的函数声明符(不是 原型格式参数类型声明器)已过时 特色


过时的功能是在未来的标准版本中可能会被删除的功能。因此,如果您希望您的代码能够经得起未来的考验,最好避免使用。

正如@StoryTeller中提到的,使用带空括号的函数声明器是一种过时的功能,但可以避免:

#include    <stdio.h>
#include    <stdlib.h>

typedef void    funp(void);

static  void    funcall( funp* F, int args, double x)
{
    switch( args)
    {
        case    0:
            F();
            break;
        case    1:  
            {
                typedef void fn(double);
                ((fn *)F)(x);
            }
            break;
    }
}

static  void    fun0( void)
{
    printf( "zero\n");
}

static  void    fun1( double x)
{
    printf( "one\t%f\n", x);
}

int main( void )
{
    funcall( (funp*)fun0, 0, 17.0);
    funcall( (funp*)fun1, 1, 17.0);
    return EXIT_SUCCESS;
}
#包括
#包括
typedef void funp(void);
静态void funcall(funp*F,int参数,双x)
{
开关(args)
{
案例0:
F();
打破
案例1:
{
类型定义无效fn(双);
((fn*)F)(x);
}
打破
}
}
静态void fun0(void)
{
printf(“零\n”);
}
静态空隙fun1(双x)
{
printf(“一个\t%f\n”,x);
}
内部主(空)
{
funcall((funp*)fun0,0,17.0);
funcall((funp*)fun1,1,17.0);
返回退出成功;
}
编辑:将
main
的参数列表更改为
void
,以符合要求


在回答问题时:

“此外,参数类型列表(如果两者都存在)应在参数数量上一致”似乎意味着funp和fun1的类型不兼容。投可以吗

答案是肯定的,可以投。从C11草案:

指向一种类型函数的指针可以转换为指向另一种类型函数的指针,然后再转换回来;结果应与原始指针进行比较。如果使用转换的指针调用类型与引用类型不兼容的函数,则行为未定义


在代码中,指向
fun1
的指针在调用
funcall
时已转换为不同的函数指针类型,并在
funcall
中转换回原始类型,因此可用于调用
fun1

,而不是对特定问题的回答,但常用的方法是只使用一个函数指针,它接受
void*
参数,然后根据实际实现对其进行不同的解释。然后,该参数可以是从
NULL
到指向具有十几个参数的结构的指针的任何内容。如果调用者必须知道参数的数量、类型和顺序,那么整个想法在实践中就不那么有用了。你发布的代码中的间距让我非常生气。最好从
main
中删除强制转换。通常,此类强制转换可能会导致编译器禁止诊断错误的c语言