Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using void (*)() pointers for other functions

Is it legal to access pointers to functions with varying argument lists in via a void (*f)() pointer? The program below compiles without warnings with gcc and appears to run correctly, but is it legal C?

#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; } 

I compiled this with

gcc -Wpedantic -Wall -Wextra -std=gnu11 -O2 -o ./funp funp.c 

It would be undefined behavior if the nargs parameter didn't match the number of arguments the function took, but is it legal if there is a match?

like image 997
dmuir Avatar asked May 21 '20 11:05

dmuir


People also ask

Can a void pointer point to a function?

void * can point to a valid objects, one byte after the last object of an array or to NULL , but functions are not objects. What you can do is converting between different pointer to function. But please keep in mind that you have to cast the function pointer back to the right type before you call the function pointer.

What does void * func () mean?

Void functions, also called nonvalue-returning functions, are used just like value-returning functions except void return types do not return a value when the function is executed. The void function accomplishes its task and then returns control to the caller. The void function call is a stand-alone statement.

Can void pointer point to any type of data?

The pointer to void can be used in generic functions in C because it is capable of pointing to any data type. One can assign the void pointer with any data type's address, and then assign the void pointer to any pointer without even performing some sort of explicit typecasting.

Can a void pointer point to anything in C?

void pointer in C / C++ A void pointer can hold address of any type and can be typecasted to any type.


1 Answers

In this particular case, the calls are legal.

Section 6.7.6.3p15 of the C standard spells out what makes two function type compatible (relevant part in bold):

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.)

So you have a typedef with type:

void() 

And functions with type:

void(void) void(double) 

The two function definitions don't use ellipsis (...) so that satisfies the fist condition. For the second condition, let's look at what the default argument promotions are. Those are specified in section 6.5.2.2p6:

If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions.

The first function has no arguments, so it is compatible. The second function has a single double argument, which matches the default argument promotions, so it is also compatible.

To give some more examples, the following functions would also be compatible:

void f1(long); void f2(int); 

But these would not:

void f3(float); void f4(char); void f5(short); 
like image 186
dbush Avatar answered Oct 22 '22 04:10

dbush