Functions of varying arity called through pointers to functions of unspecified arguments - c

I'm 99% convinced that this is legitimate after reviewing the C standard and several comp.lang.c posts, but am hoping that someone can provide the precise language in the standard that allows (or forbids) this case:
#include <stdio.h>
double id (double x) { return x; }
double add2 (double x, double y) { return x + y; }
double add3 (double x, double y, double z) { return x + y + z; }
typedef double (*fp) ();
static fp funcs[] = { id, add2, add3 };
int main (void)
{
printf("id(5.3) = %f\n", funcs[0](5.3));
printf("add2(5.3, 6.1) = %f\n", funcs[1](5.3, 6.1));
printf("add3(5.3, 6.1, 7.2) = %f\n", funcs[2](5.3, 6.1, 7.2));
return 0;
}
The provided example gave the expected results for me under MinGW gcc 4.4.0 using -Wall -pedantic -ansi.
Considerations:
I'm aware that calls to functions with unspecified parameters implicitly promote integral arguments according to the integral promotion rules and float arguments to double. Does this behavior change in any way when calling through a function pointer to a function of unspecified parameters? (I don't see why it would.)
I came across several posts implying that calls to functions with ... specifiers (e.g. double uhoh (double x, ...)) are not permitted through function pointers to functions of unspecified parameters. This makes sense from an implementation perspective, but I haven't been able to pin down the clause in the standard which forbids this.

First I can suggest that the standard function call syntax:
void foo(int);
foo(3);
is defined in terms of foo decaying to a function pointer, then being invoked; therefore I don't see why there would be any difference between your situation and a "standard" function call.
Second, n1256 6.5.2.2 details function call semantics, and it seems pretty well-defined for a function pointer with no prototype provided the number and type of arguments matches the number and type of parameters.
An empty parameter list is incompatible with a variadic parameter list according to n1256 6.7.5.3p15:
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.
This means it is a constraint violation (6.5.16.1p1) to assign a variadic function pointer to a pointer-to-function with no prototype, since you are assigning pointers to incompatible types.
I would guess that casting a variadic function pointer to a non-prototyped function pointer is also UB and possibly a CV; but I haven't checked.

You are correct that this program has entirely well-defined behavior as long as the arguments when you make the call are of the number and types matching those in the definition of the function that gets called. See 6.5.2.2 paragraph 6. My related question may also be of interest:
Is this dubious use of a non-prototype function declaration valid?

The code is well-defined as long as all parameter types promote to themselves and all supplied argument are of correct type.
If you want to get back some measure of type-safety, you could use explicit casts or unions, eg
#include <stdio.h>
static double id(double x) { return x; }
static double add2(double x, double y) { return x + y; }
static double add3(double x, double y, double z) { return x + y + z; }
union func
{
double (*as_unary)(double x);
double (*as_binary)(double x, double y);
double (*as_ternary)(double x, double y, double z);
};
static const union func funcs[] = {
{ .as_unary = id },
{ .as_binary = add2 },
{ .as_ternary = add3 }
};
int main(void)
{
printf("id(5.3) = %f\n", funcs[0].as_unary(5.3));
printf("add2(5.3, 6.1) = %f\n", funcs[1].as_binary(5.3, 6.1));
printf("add3(5.3, 6.1, 7.2) = %f\n", funcs[2].as_ternary(5.3, 6.1, 7.2));
return 0;
}

Related

too many arguments for function error but function clearly takes two arguments

code to ask user to input base and power and prints result:
#include <stdio.h>
int main()
{
float v;
int power;
printf("Enter value of x:\t");
scanf("%f", &v);
printf("Enter power:\t");
scanf("%d", &power);
v = exp(v, power);
printf("%.2f", v);
}
float exp(float n, int i) {
float base = n;
int power = i;
float result = 1;
while (power != 0)
{
result = result * base;
--power;
}
return result;
}
compiler spits out:
x.c:11:6: error: too many arguments to function ‘exp’
11 | v = exp(v, power);
| ^~~
clearly:
float exp(float n, int i) {
takes two arguments. What's going on here?
It's because your exp function is not known by the compiler yet.
exp is built-in function in C.
The function prototype of exp() is: double exp(double x);
To make your program work, you should put your exp function above main function.
Two things are happening here.
You have not declared or defined exp() before use
Your compiler has a built-in for exp() with a different signature
I am not sure what compiler you are using but I would be surprised if there were not also warnings explaining this. GCC produces:
main.c: In function ‘main’:
main.c:12:11: warning: implicit declaration of function ‘exp’ [-Wimplicit-function-declaration]
v = exp(v, power);
^~~
main.c:12:11: warning: incompatible implicit declaration of built-in function ‘exp’
main.c:12:11: note: include ‘’ or provide a declaration of ‘exp’
main.c:12:11: error: too many arguments to function ‘exp’
main.c: At top level:
main.c:18:9: warning: conflicting types for built-in function ‘exp’
float exp(float n, int i) {
^~~
Providing a prototype solves the problem:
float exp(float n, int i) ;
int main()
{
...
}
However it is probably ill-advised. The standard library function exp() computes e (Euler's number, 2.7182818...) raised to the given power the single argument, so is semantically different that your exp().
Overriding a standard library function in this way is in any case ill advised even if it has the same semantics. I strongly suggest that you use a different name such as power() for example (not pow() - that is also a standard library function).

C Why function pointer as parameter instead of just a function?

I have been reading about having functions with functions as parameters, and particulary in C, they use function pointers. Let's suppose I want to implement the newton raphson method (in a simple way) for computing zeros in non linear equations.
double derivative(double f(double), double x)
{
double h = 1e-9;
return (f(x + h) - f(x)) / h;
}
double newton_raphson(double f(double), double x0, double tol)
{
double xk, diff;
do
{
xk = x0 - f(x0) / derivative(f, x0);
diff = fabs(xk - x0);
x0 = xk;
} while (diff >= tol);
return xk;
}
So, to compute an approximation for derivative I need a function that returns a double and takes a double as an argument. Same for computing a root of the function, given the other parameters. My question is, why is this different from declaring function parameters as function pointers? For instance declaring the input parameter f as a function pointer instead of just a function...
The parameter f is a pointer-to-function in both derivative and newton_raphson.
double derivative(double f(double), double x) { ... }
is exactly equivalent to
double derivative(double (*f)(double), double x) { ... }
Only, the former looks nicer - usually when you can omit parentheses, you should probably do so. After all both of them are equivalent to
double ((((derivative)))(double (((*(f))))(double ((trouble))), double ((x)))) { ... }
That I hope will only ever be used in IOCCC.
However, if you're declaring, defining a variable (not a function parameter), you need to use
double (*f)(double);
as
double f(double);
is just a function declaration.
6.7.6.3 Function declarators (including prototypes) of C11 draft n1570 says:
A declaration of a parameter as ‘‘function returning
type
’’ shall be adjusted to ‘‘pointer to
function returning
type
’’, as in 6.3.2.1.
And
6.9.1 Function definitions further says that
[...] the type of each parameter is adjusted as described in 6.7.6.3 for a parameter type list; the resulting type shall be a complete object
type.
additionally it has the following example:
EXAMPLE 2
To pass one function to another, one might say
int f(void);
/* ... */
g(f);
Then the definition of g might read
void g(int (*funcp)(void))
{
/* ... *
(*funcp)(); /* or funcp(); ... */
}
or, equivalently,
void g(int func(void))
{
/* ... */
func(); /* or (*func)(); ... */
}
Like normal data pointers, a function pointer can be passed as an argument and can also be returned from a function. A function’s name holds the address of function.
My question is, why is this different from declaring function parameters as function pointers? For instance declaring the input parameter f as a function pointer instead of just a function...
The answer is that both forms will be treated as same by compiler.
But for readibility of your code, go with the kind of declaration that your example code has, i.e.,
double derivative(double f(double), double x) { ... }
Even in C, the function definitions given below will be interpreted as same-
void foo(int a[]) // or int a[10]
{
...
}
void foo(int *a)
{
...
}

C function pointer cast to another function pointer

I need help in function pointers.
I have two function pointer types:
typedef void (*draw_func1_t)(void* data, void* painter, double x, double y);
typedef void (*draw_func2_t)(void* data, MyPainter* painter, double x, double y);
The two types are almost the same, except the second parameter. Now I need to write a function that convert a draw_func1_t to draw_func2_t:
draw_func2_t convert_func_p(draw_func1_t func) { ... }
How can I write it? Can I just force a cast like
return (draw_func2_t)func;
because the two function prototypes are binary compatible?
If you cast a function pointer to a different type, then the behaviour on its calling is undefined. See Annex J.2 of the C standard:
The behaviour is undefined in the following circumstances: A pointer
is used to call a function whose type is not compatible with the
pointed-to type (6.3.2.3).
Compatibility is dealt with in 6.7.5.1, paragraph 2:
For two pointer types to be compatible, both shall be identically
qualified and both shall be pointers to compatible types.
A MyPainter* is not compatible with a void*. So your function pointer cast cannot be used to call the function.
Since use of:
draw_func1_t convert_func_p(draw_func2_t func)
{
return (draw_func1_t)func;
}
leads to undefined behavior, you might want to change your strategy.
Say you have:
void func2(void* data, MyPainter* painter, double x, double y)
{
printf("In func2, working with MyPainter\n");
}
and you would like to be able use that function indirectly through a function pointer.
One option is to use a wrapper function.
void func2_wrapper(void* data, void* painter, double x, double y)
{
// In this function, if you are sure that painter points to
// a valid MyPainter object, you can do this:
MyPainter* realPainter = (MyPainter*)painter;
// Then call the core function.
func2(data, realPainter, x, y);
}
Register func2_wrapper as a callback.
You can also make func2_wrapper simpler by removing the explicit cast to MyPainter*.
void func2_wrapper(void* data, void* painter, double x, double y)
{
func2(data, painter, x, y);
}
Theoretically, if you cast it to a different signature and call it, it is undefined behavior, as Bathsheba's answer cites, because the calling convention for calling different types of functions can be different.
However, practically, it will work on pretty much any real-world system, because pretty much all calling conventions treat different types of (non-function) pointers identically. And since that's the only difference (everything else, including the number of parameters and return type are the same), the calling conventions will almost certainly be the same. You can check the function-calling ABI for your specific system to make sure.
The following compiles without warnings (VC2008) and shows that the two function types are compatible. Unexpectedly, a void * is accepted where a MyPainter * is requied.
typedef struct {
int x;
int y;
} MyPainter;
typedef void (*draw_func1_t)(void* data, void* painter, double x, double y);
typedef void (*draw_func2_t)(void* data, MyPainter* painter, double x, double y);
void f1(void* data, void* painter, double x, double y);
void f2(void* data, MyPainter* painter, double x, double y);
void f1(void* data, void* painter, double x, double y)
{
f2(data,painter,x,y); // no compiler warning is unexpected
}
void f2(void* data, MyPainter* painter, double x, double y)
{
f1(data,painter,x,y); // no compiler warning is expected
}
void pTest(void)
{
MyPainter p = {0,0};
draw_func1_t pf1;
draw_func2_t pf2;
pf1= f1;
pf2= f1;
pf1= f2;
pf2= f2;
pf1(0,&p,0.0,0.0);
pf2(0,&p,0.0,0.0);
}

expected expression before double

Keeps saying that there is an expected expression before double int pt function
#include <stdio.h>
int pt (int a, int b)
{
int c, result;
c = (a * a) + (b + b);
result = double sqrt (double c);
return result;
}
int main (void)
{
int d, e, f;
int pt (int a, int b);
printf("type enter after input of the two legs");
scanf("%i", &d);
scanf("%i", &e);
f = pt (d,e);
printf("the hypotenuse is %i", f);
return 0;
}
Change
result = double sqrt (double c);
to
result = sqrt(c);
You don't have to cast c into a double when you pass it into the sqrt function because of implicit conversion. If you still wanted to do the cast, the correct way would be sqrt((double) c).
Also, #include <math.h> for use of the sqrt function.
Note: It's not required to cast the return type of sqrt to int (relevant since result is of type int) - however some compilers may give warnings about implicit conversion (Credit to #MattMcNabb). It can also be good practice to put the cast in to signal to other coders that the precision loss is intentional.
double sqrt (double c); is a function declaration. (It is also a function prototype). This is how you announce that a function exists, and what parameters it takes and what it returns. The word c here does not mean anything, it can be omitted.
When you want to call a function you do not repeat this info. You just give the function name, followed by a list of values, e.g. sqrt(c) .
In your code , sqrt has not been declared. Functions must be declared before they are called. It's not possible to simultaneously declare a function and call it; you have to declare it first.
(Historical note: this is true from C99 onwards; in C89 you could call an undeclared function, and the compiler would assume you wanted the function declared to return int ; this would cause undefined behaviour for any function that does not actually return int).
It is possible for you to provide your own declaration, so long as it matches the standard declaration:
double sqrt(double);
However it is a better idea to just use the standard declaration by going:
#include <math.h>
which works because the file math.h includes the line double sqrt(double); (or something equivalent).
Then you can write:
result = sqrt(c);
Note that you do not need to use any casts in relation to this function call. Since a function prototype exists, the compiler knows that even if you supply an int, it should convert that int to a double (which it knows how to do), and vice versa.
It is talking about the casting that you are doing?
your casting is complaining it should be like this:
your result is an integer, so you should be casting it to int..
but if you want to cast anything to double it should be as follow
result = (double)sqrt((double) c)
or another way is double(sqrt((double) c)
but if you want to cast it as int then
result = (int)sqrt((double) c)
or
result = int(sqrt((double) c))
hope this helps good luck

why this program is not showing any error?

in the code below .
i have defined function prototype with no argument
in definition as well as in function call i have used one parameter.
i would like to know why i am not getting any error ?
# include <stdio.h>
float circle(); /* no parameter*/
int main()
{
float area;
int radius =2;
area=circle(radius);
printf("%f \n",area);
return 0;
}
float circle( r) /* with one parameter even no parameter type */
{
float a;
a=3.14*r*r;
return (a);
}
The
float circle();
is not a function with zero parameters. It's a function with an unspecified number of parameters.
The
float circle( r) {
is a K&R-style definition in which the type of r defaults to int. See https://stackoverflow.com/a/18433812/367273
This is because compiler treat r as int by default when no parameter is defined for circle. Try to run your code after declaring function prototype as
float circle(void);
and you will get error.
That's because function
float circle();
declaration doesn't declare function that takes no arguments.
It's implicitly declared as a function that takes undefined number of integer variables as arguments.
Just like
function();
is valid function declaration. Implicitly this function will be treated as function taking int as arguments and returning int.
If you want to declare function function taking no arguments or not returning any value, you do it with void keyword:
void funct(void);

Resources