简体   繁体   中英

variadic function to function pointer

Is There any way to cast a variadic function to a function pointer like this, is it legal? I am asking both for C and for C++, but since this construct exists in both languages, I have put both questions in one.

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

Thanks, thejack

C-style variadic functions are their own special beast. Their arguments must be unwrapped with the va_list family of functions. There is no compatibility with non-variadic functions, and they are not macros, and no.

Given your use of auto I assume that you're asking about C++, despite the double-tagging. Try to avoid functions like that in C++.

You are free to cast a function pointer to a function pointer of a different type, but calling a function through a function pointer of a different type is undefined behaviour. (So the only valid thing you can do with the cast function pointer is to cast it back to rhe correct type.)

Variadic functions are not the same type as functions with a specific number of arguments. So the result of the cast cannot be used to call the function.

If you try it on some compiler, you might find that it does what you expect. But that doesn't make it valid; it may well break on a different platform or compiler version.

(The above is true for both C and C++.)

In C, these types are not compatible.

Section 6.2.7 of the C standard regarding "Compatible type and composite type" says the following regarding the compatibility of function pointers:

3 A composite type can be constructed from two types that are compatible; it is a type that is compatible with both of the two types and satisfies the following conditions:

  • If both types are array types, the following rules are applied:
    • If one type is an array of known constant size, the composite type is an array of that size.
    • Otherwise, if one type is a variable length array whose size is specified by an expression that is not evaluated, the behavior is undefined.
    • Otherwise, if one type is a variable length array whose size is specified, the composite type is a variable length array of that size.
    • Otherwise, if one type is a variable length array of unspecified size, the composite type is a variable length array of unspecified size.
    • Otherwise, both types are arrays of unknown size and the composite type is an array of unknown size. The element type of the composite type is the composite type of the two element types.
  • If only one type is a function type with a parameter type list (a function prototype), the composite type is a function prototype with the parameter type list.
  • If both types are function types with parameter type lists, the type of each parameter in the composite parameter type list is the composite type of the corresponding parameters.

...

5 EXAMPLE Given the following two file scope declarations:

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

The resulting composite type for the function is:

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

Section 6.7.6.3p15 states:

For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters, and the type of each prototype parameter shall be compatible with the type that results from the application of the default argument promotions to the type of the corresponding identifier. (In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.)

In your example:

int test(int, ...);

This function is compatible with the following:

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

But not:

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

Because both function type specify a parameter list and because the number of parameters nor does the use of ellipsis agree, the types are not compatible. Attempting to call a function through an incompatible pointer invokes undefined behavior as per section 6.3.2.3p8:

A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM