Sorry, but I'm a bit confused about using function pointers. I typed 3 functions which use function pointer in different ways, but incredibly they all worked.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef int(*pfun)(int a, int b);
int add(int a, int b)
{
return a + b;
}
int f1()
{
pfun fun = add;
return fun(3, 4);
}
int f2()
{
pfun fun = &add; //Why did't compiler report an error?
return fun(3, 4); //Why it could work? The value in fun should be a pointer of function pointer.
}
int f3()
{
pfun fun = &add;
return (*fun)(3, 4); //Why did't compiler report an error?
}
int main()
{
printf("%d,%d,%d\n", f1(),f2(),f3());
system("pause");
return 0;
}
The output is 7,7,7 with no compile error in VS2017.
In f2 your comment is wrong. &add could not possibly be a pointer-to-pointer; what pointer object would it point to? Likewise, given char array[N];, &array is not a pointer-to-pointer. It has pointer-to-array type. Both function and array type identifiers evaluate to pointers (pointer-to-function or pointer-to-first-element, respectively) in most contexts, but that does not mean that they have pointer type themselves.
In f3, *fun is an expression evaluating to a function, which always converts implicitly to a pointer to the function. There is simply no such thing as an expression with function type. Therefore, ****************fun also evaluates to the same thing as fun (a pointer to add).
Note that the function call operator () takes as its operand an expression with pointer-to-function type. Whenever you call a function by its identifier, you are using a function pointer.
Per the language, none of these forms are any more "right" than any other, but I think most C programmers find use of & and * operators at best redundant (if not misleading) with functions, and would consider f1 the best.
There is no difference between add and &add. Both expressions represent the adress of the function.
As for
fun(3, 4);
// vs.
(*fun)(3, 4);
it doesn't matter whether the function pointer is dereferenced implicitly or you do it explicitly.
Related
Let's say I have something like the following to call a function in C:
void test1(void) {
int a=7;
function((short) a);
}
Does the compiler treat this (almost) the same as if it were to create a temporary variable and pass that to the function, for example:
void test1(void) {
int a=7;
short tmp_a=(short) a;
function(tmp_a);
}
Or does the cast do anything differently than the above, at least on a conceptual level?
Casts are just operators, like multiplication or shifts. When a function argument is an expression, it is evaluated like any other expression. So function((short) a); is equivalent to:
short tmp_a = (short) a;
function(tmp_a);
in the same way that function(a*a); is equivalent to:
int tmp_a = a*a;
function(tmp_a);
Note there are also implicit conversions involved in function calls. If the function has a prototype, arguments are converted to the declared types of the parameters. If there is no prototype, or an argument corresponds to the ... part of a prototype, some default argument promotions are performed.
I was messing around with function pointers, and I noticed something with the following program:
#include <stdio.h>
int operation (int x, int y, int (*fptr)(int, int))
{
int z;
z = (*fptr)(x, y);
return (z);
}
int add(int a, int b) {
return a+b;
}
int main(int argc, char** argv) {
/* This line */ printf("%d\n", operation(1, 2, add));
}
Running this program results in 3, as it should.
However, on the line marked /* This line */, I noticed that if the line was changed to any of the these other two options, it also resulted in 3:
printf("%d\n", operation(1, 2, *add) and printf("%d\n", operation(1, 2, &add) (notice the added asterisk and ampersand).
It also works when I tried things like printf("%d\n", operation(1, 2, *(&add))); and printf("%d\n", operation(1, 2, &(*add))); (which I assumed after seeing the above).
I was wondering why this is, and if there is any difference between the two options. Is this undefined behavior and I'm just getting lucky, does the compiler assume that by all of these I mean the same thing, or is there something weird going on here I don't understand?
From the ANSI/ISO 9899-1990 C standard, section 6.2.2.1:
A function designator is an expression that has function type. Except when it is the operand of the sizeof operator or the unary & operator, a function designator with type "function returning type" is converted to an expression that has type "pointer to function returning type."
This means that add by itself is converted to a pointer. &add is also a pointer, kind of by definition; I think that's why it's explicitly excluded from the paragraph above. And *add goes through a double conversion, dereferencing the function as a pointer then reinterpreting that as a pointer again.
I don't expect there would be any difference in the compiled code.
Actually, function names are just labels for memory addresses, which makes them address holders like pointers. So, you can think of function names as pointers in a way. Therefore, it should not be surprising that you can use the same reference operators as you did on pointers.
I read that;
Although an array name can be used as a pointer (after decaying into pointer), it's not possible to assign it a new value. Attempting to make it point elsewhere is an error:
while (*a != 0) // a is of (int *) type
a++; //wrong
On the other hand, when passed to a function, an array name is always treated as a pointer. The function call
largest = largest_num(b, n) // b is an array of int
for the function
int find_largest(int a[], int n)
{
....
....
}
causes a pointer to the first element of b to be assigned to a.
Above two statements ( in bold ) seems to me contradictory. I am confused.
In a function declaration, an array is treated as if you'd declared a pointer, so
int find_largest(int a[], int n) {
is processed as if it were
int find_largest(int *a, int n) {
So a is a pointer, not an array, and there's no contradiction.
Since it's a pointer, you can reassign a, e.g.
a++;
is allowed.
No contradiction there - you're still working with a pointer (to int), and int a[] notation is allowed only for convenience. Quoting the comp.lang.c FAQ:
Since arrays decay immediately into pointers, an array is never
actually passed to a function. You can pretend that a function
receives an array as a parameter, and illustrate it by declaring the
corresponding parameter as an array:
void f(char a[])
Interpreted literally, this declaration would have no use, so the
compiler turns around and pretends that you'd written a pointer
declaration, since that's what the function will in fact receive:
void f(char *a)
This conversion of array-like declarators into pointers holds
only within function formal parameter declarations, nowhere else. If
the conversion bothers you, you're under no compulsion to make use of
it; many programmers have concluded that the confusion it causes
outweighs the small advantage of having the declaration ``look like''
the call or the uses within the function.
consider the following code:
#define MAX_COUNT 4
static int foo(int w[MAX_COUNT])
{
int *p = w;
if (w) {
w[0] = 10; w[1] = 20; w[2] = 30; w[3] = 40;
}
return 0;
}
is it portable and legal pass NULL to above defined foo() (for example, for a situation when I don't need w[] be altered)? Given that the name of an array is a pointer to its first element, it seems to me that it should be OK, but perhpas I'm missing something?
Thanks !
In C, an array type function parameter is the same as a pointer type, so the following are the same:
static int foo(int w[]);
static int foo(int* w);
So, yes, it is legal to pass NULL to this function.
Given that the name of an array is a pointer to its first element
Not quite. An array decays to a pointer to its initial element under most circumstances, the exceptions being when it is the operand of sizeof or the unary & operator (the address-of operator).
It should be fine. The number of elements in the array that you passed are merely a formalism, and not really needed. w is just a pointer to int. There is no other runtime or compilation check.
C99 has the construct with the awfull syntax (for your example)
static int foo(int w[static MAX_COUNT]);
which basically means that the function expects at least MAX_COUNT
elements. Calling such a function with NULL would then be considered
as an error.
Unfortunately this feature is not yet widely implemented. e.g gcc
and clang just accept the syntax but don't do anything useful with the
information.
everyone, I have this piece of the code:
void foo(int var, int var1)
{
printf("%d\n", var);
printf("%d\n", var1);
}
void foo_for_foo( void (*some_function)(int, int))
{
int x = 5;
some_function(x, x);
}
int main()
{
void (*ptr_foo); // <- look here
ptr_foo = &foo;
foo_for_foo(ptr_foo);
return 0;
}
does it matter how do I define pointer to function:
1) void (*ptr_foo);
2) void (*ptr_foo)(int, int);
my compiler receives both versions
thanks in advance for the explanations of the difference
The two forms are not equivalent.
void (*ptr_foo) is not a function pointer at all. It's a normal, non-function void pointer. The parentheses are superfluous and misleading. It's exactly as if you had written void* ptr_foo.
void (*ptr_foo)(int, int) is the proper way to declare a function pointer to a function taking two ints and returning void.
The only reason that this works is because in C, void pointers are implicitly convertible to any other type of pointer. That is, you can assign any other pointer to a void*, and you can assign a void* to any other pointer.
But the fact that this works in this example is essentially an accident of syntax. You cannot in general replace void (*foo)(int, int) with void (*foo).
If you try doing that with some_function in the argument list to foo_for_foo, your compiler will complain when you try to invoke some_function because it is not a function pointer.
Similarly, if your foo function happened to return an int instead of void, you would notice the problem right away. Declaring ptr_foo as int (*ptr_foo) would have resulted in an error on the statement ptr_foo = &foo because unlike void pointers, int pointers are not implicitly convertible to other pointer types.
In short, always use the second form. It is the only one that is correct in general, despite this fluky case.
The statement void (*ptr_foo); declares a variable of type void *. The function pointer is cast to this type in the statement ptr_foo = &foo; and back to a pointer to the proper function pointer type in the call to foo_for_foo. If you compile with gcc -Wall (or whatever extra paranoid settings your compiler supports) you should see a warning about this conversion.