可变参数到函数指针

时间:2019-01-02 13:33:38

标签: c++ function variadic-functions

有什么方法可以将可变参数转换为这样的函数指针,这合法吗?我同时问C和C ++,但是由于这种结构同时存在于两种语言中,因此我将两个问题都放在一个语言中。

extern int test(int, ...);
auto testptr = (int(*)(int, int, long)) &test;

谢谢, 劫机者

3 个答案:

答案 0 :(得分:5)

C风格的可变参数功能是它们自己的特殊野兽。它们的参数必须与va_list函数系列一起使用。与非可变函数不兼容,它们不是宏,也不是。

考虑到您使用auto,尽管有双重标记,我认为您仍在询问C ++。 Try to avoid functions like that in C++.

答案 1 :(得分:3)

您可以随意将函数指针转换为其他类型的函数指针,但是通过其他类型的函数指针调用函数是未定义的行为。 (因此,您只能使用强制转换功能指针执行的正确操作就是将其强制转换为正确的类型。)

可变参数函数与带有特定数量参数的函数的类型不同。因此,强制转换的结果不能用于调用该函数。

如果在某些编译器上尝试使用它,则可能会发现它执行了预期的操作。但这并不能使它有效。可能会在其他平台或编译器版本上中断。

(以上对于C和C ++都是正确的。)

答案 2 :(得分:1)

在C中,这些类型兼容。

C standard中有关“兼容类型和复合类型”的第6.2.7节对功能指针的兼容性进行了以下说明:

  

3 可以从两种兼容的类型构造复合类型;它是与两种类型都兼容的类型   并满足以下条件:

     
      
  • 如果两种类型都是数组类型,则将应用以下规则:      
        
    • 如果一种类型是已知大小的数组,则复合类型是该大小的数组。
    •   
    • 否则,如果一种类型是可变长度数组,其大小由未求值的表达式指定,则   行为是不确定的。
    •   
    • 否则,如果一种类型是指定了大小的可变长度数组,则复合类型是以下类型的可变长度数组:   那个大小。
    •   
    • 否则,如果一种类型是未指定大小的可变长度数组,则复合类型是未指定大小的可变长度数组   大小。
    •   
    • 否则,这两种类型都是未知大小的数组,而复合类型是未知大小的数组。的元素类型   复合类型是两个元素的复合类型   类型。
    •   
  •   
  • 如果只有一种类型是带有参数类型列表的函数类型(函数原型),则复合类型是函数   参数类型列表的原型。
  •   
  • 如果两种类型都是带有参数类型列表的函数类型,则复合参数类型列表中每个参数的类型为   相应参数的复合类型。
  •   
     

...

     

5 示例给出以下两个文件作用域声明:

int f(int (*)(), double (*)[3]);
int f(int (*)(char *), double (*)[]);
     

该函数产生的复合类型为:

int f(int (*)(char *), double (*)[3]);

第6.7.6.3p15节规定:

  

要使两种功能类型兼容,均应指定   兼容的返回类型。 此外,参数类型   清单(如果同时存在)应在   参数以及省略号终止符的使用;   相应的参数应具有兼容的类型。如果一种   有一个参数类型列表,另一个类型由   不属于函数定义的函数声明符   包含一个空的标识符列表,参数列表   不得带有省略号和每个参数的类型   应与由   应用默认参数提升。如果一种类型具有   参数类型列表,其他类型由函数指定   定义包含(可能为空)标识符列表,两者   应在参数数量和类型上达成共识   每个原型参数应与类型兼容   这是由于应用默认参数导致的   提升为相应标识符的类型。 (在   类型兼容性和复合材料的确定   类型,使用函数或数组类型声明的每个参数为   视为具有调整后的类型,并且每个参数都用声明   限定类型被视为具有其非限定版本   声明的类型。)

在您的示例中:

int test(int, ...);

此功能与以下设备兼容:

int (*)();            // a function taking an unknown number of parameters and returns an int
int (*)(int, ...);    // a function taking an int and variable parameters after and returns an int

但不是:

int (*)(int, int, long);    // a function taking an int, an int, and a long, and returns an int

因为两种函数类型都指定了一个参数列表,并且由于参数的数量也没有使用省略号而导致它们不兼容,所以这些类型是不兼容的。尝试通过不兼容的指针调用函数会根据6.3.2.3p8节调用undefined behavior

  

指向一种类型的函数的指针可以转换为指向   另一种功能并再次返回;结果应进行比较   等于原始指针。 如果使用转换后的指针进行调用   一个类型与所引用类型不兼容的函数,   行为是不确定的。