Declaration of function pointers - c

To declare a function pointer using typedef, it will be something like:
typedef void (*FOO)(int i)
But normally the syntax for typedef is like:
typedef int BOOL
so why is the first one not:
typedef void (*)(int) FOO
To return a function pointer (without typedef), the syntax is as follow:
void (*foo(char c))(int)
which means foo takes in a char and returns a pointer to a function which takes an int and returns nothing. The syntax is so weird! It looks like foo takes in an int and returns nothing. The parentheses don't seem to be in the right places. If it is to return a function pointer, why is it not something like:
(void (*)(int)) foo(char c)
which is very straightforward. I am really having trouble understanding the syntax here, let alone using it. Can someone please explain what's going on here?

An integer is just:
int x;
A name for the above is given by:
typedef int x_type;
A pointer to an int is:
int *p;
It's type would be:
typedef int *p_type;
A function called foo taking a double``and returning anint` is:
int foo(double);
Defining the type of foo would be:
typedef int foo_type(double);
Now a pointer to the above should take an *, but () (function call) binds tighter than * (dereference), so parentesis:
typedef int (*ptr_to_foo_type)(double);
This might be better written:
typedef foo_type *ptr_to_foo_type;
as some suggest writing for clarity.
The idea is that the type description looks (somewhat) like its use. Badly mangled idea, given prefix/postfix operators, that much everybody agrees on. But it is now much too late to change.

Declaration syntax is based on the types of expressions, not objects. Another way of saying it is that "declaration mimics use".
Let's start with a simple pointer expression; call it iptr. iptr points to an integer value. If we want to access that value, we need to dereference iptr with the unary * operator, like so:
x = *iptr;
The expression *iptr has type int, so the declaration of iptr is written
int *iptr;
If you wanted to create a typedef for an int pointer, you would add the typedef to get
typedef int *iptr;
iptr now serves as a synonym for type "pointer to int", so you can write
iptr ip;
which declares ip as a pointer to int (as a rule, you really don't want to hide pointers in typedefs).
Now let's say you have a pointer to a function that takes two int arguments and returns an int value, call it fp. To call the function, you dereference the pointer and pass the necessary arguments to the resulting function, like so:
x = (*fp)(arg1, arg2); // C allows you to omit the * in the call, so you could
// also write it as simply x = fp(arg1, arg2), but we're
// leaving it in so the following explanation makes sense
The function call () operator has higher precedence than unary *; *fp() will be interpreted as *(fp()), which is not what we want. To dereference fp before calling the function it points to, we must explcitly group the * operator with fp.
The type of the expression (*fp)(arg1, arg2) is int, so the declaration of fp becomes
int (*fp)(int arg1, int arg2);
Let's look at your second example now: foo is a function that takes a char argument and returns a pointer to a function that takes an int argument and returns void. You'd call it as something like
(*foo(c))(x);
Again, the type of the expression (*foo(c))(x) is void, so it follows that the declaration is
void (*foo(char c))(int x);
For syntactic reasons, typedef is treated as a storage class specifier like extern or static, although it has a very different meaning. It doesn't change the structure of a declaration; it just changes how that declaration is interpreted by the compiler. Adding typedef to the above, as in
typedef void (*foo(char c))(int x);
now creates the synonym foo for the type "function returning pointer to function returning void". It's no different from how simpler type definitions like
typedef int *iptr;
behave.

1) The syntax for typedef is to take a declaration of a variable of that type and put typedef in front of it.
2) The syntax for declarations echos the syntax for actually obtaining a value of that type. See my other recent answers regarding precedence of addressing operators (including function call), such as (*twod)[3] vs *(twod)[3] C Pointers ... I'd rather not repeat it all again.

Related

I can't understand why the command 'typedef' can be used like this

I was studying C99 - Function pointer part and my textbook offered a way to use 'typedef' for simplifying the code below :
int (*p[4])(int,int) = {&Sum,&Sub,&Mul,&Div};
↓
typedef int (*OP_TYPE)(int,int);
OP_TYPE p[4]={&Sum,&Sub,&Mul,&Div};
I've known that 'typedef' can be used only like this :
eg.
typedef unsigned short int US;
Was it not wrong, int would be altered as (*OP_TYPE)(int,int), and Isn't it right the second sentence become (*OP_TYPE)(int,int)(*p[4])(int,int) = {&Sum,&Sub,&Mul,&Div};
I can't understand why the second sentence could be like that.
The typedef keyword behaves grammatically like storage modifiers (i.e. auto, register, static etc) except the initialization part. My guess the reason for that is that the early versions of C compilers shared code between variable declaration and type alias declarations.
Therefore the type alias declaration and variable declaration look more or less the same:
static int (*A[4])(int,int); // staic variable
typedef int (*B[4])(int,int); // type alias
int (*C[4])(int,int); // local variable
I guess the question is why one cannot do:
int (*[4])(int,int) C;
I have no good answer to that, C grammar is simply defined this this way. I can guess that without the anchor the compiler cannot correctly parse the type.
So why one can't do:
(int (*[4])(int,int)) C;
Answer:
It would solve the problem with missing anchor. However, it cannot be used because it will conflict with cast operator (type) expr. Note that symbol C may be defined on out scope resulting in ambiguity.
int C;
{
// cast `C` to `int*` or maybe declare a pointer to `int`
(int*)C;
}
However, there is a workaround with typeof extension (a feature in upcoming C23).
typeof(int (*[4])(int,int)) C;
This is more or less the same how the compiler expands the following declaration:
typedef int (*OP_TYPE)(int,int);
OP_TYPE p[4]={&Sum,&Sub,&Mul,&Div};
to
typeof(int(*)(int,int)) p[4] = { ... }
Moreover, using this trick allows a neat and readable declaration of complex types.
typeof(int(int,int))* p[4] = { .... }
It is easy to see that p is a 4-element array of pointers to int(int,int) function.
Was it not wrong, int would be altered as (*OP_TYPE)(int,int), and Isn't it right the second sentence become (*OP_TYPE)(int,int)(*p[4])(int,int) = {&Sum,&Sub,&Mul,&Div};
The declaration
typedef int (*OP_TYPE)(int, int);
does not change the meaning of int - it changes the meaning of OP_TYPE.
First, some background:
Declarations in C are broken into two main sections: a sequence of declaration specifiers, followed by a comma-separated list of declarators.
The declarator introduces the name of the thing being declared, along with information about that thing's array-ness, function-ness, and pointer-ness. In a typedef, that name becomes an alias for the type.
The structure of the declarator is meant to mirror the structure of an expression in the code. For example, suppose you have an array arr of pointers to int and you want to access the integer object pointed to by the i’th element; you’d index into the array and dereference the result, like so:
printf( "%d\n", *arr[i] ); // *arr[i] is parsed as *(arr[i])
The type of the expression *arr[i] is int; that's why we write its declaration as
int *arr[N];
instead of
int *[N] arr;
In the expression, the operand of the postfix [] subscript operator is arr, and the operand of the unary * dereference operator is the expression arr[i]. Those operators follow the same rules of precedence in a declaration, hence the structure of the declaration above.
The declaration reads as
arr -- arr
arr[N] -- is an array of
*arr[N] -- pointer to
int *arr[N]; -- int
Thus, object named arr has type "array of pointer to int";
Similarly, if you have an array of function pointers and you want to call one of those functions, you’d index into the array, dereference the result, and then call the resulting function with whatever arguments:
x = (*p[i])(a, b);
Again, the type of the expression (*p[i])(a, b) is int, so it follows that the declaration of p is written
int (*p[4])(int, int);
and not
int (*[4])(int, int) p;
Again, the declaration reads as
p -- p
p[4] -- is a 4-element array of
*p[4] -- pointer to
(*p[4])( ) -- function taking
(*p[4])( , ) -- unnamed parameter
(*p[4])(int, ) -- is an int
(*p[4])(int, ) -- unnamed parameter
(*p[4])(int, int) -- is an int
int (*p[4])(int, int); -- returning int
so the object named p has the type "array pointer to function taking two int parameters and returning int".
Clear so far?
So, how does typedef affect this?
Let's start with a declaration without the typedef:
int (*OP_TYPE)(int, int);
This declares OP_TYPE as an object of type "pointer to function taking two int parameters and returning int". If we add the typedef keyword:
typedef int (*OP_TYPE)(int, int);
it changes the meaning of the declaration such that OP_TYPE is an alias for the type "pointer to function taking two int parameters and returning int". It doesn't change the structure of the declaration at all, only the meaning. Thus, you can write
OP_TYPE fp;
and it will mean exactly the same thing as
int (*fp)(int, int);
Some other examples may help drive the concept home; going back to the earlier examples, if
int *ap[N];
declares ap as an object of type "4-element array of pointer to int", then
typedef int *ap[N];
declares ap as an alias for the type "4-element array of pointer to int", such that
ap foo;
is equivalent to
int *foo[N];
If
int (*blah)[N];
declares blah as an object of type "pointer to N-element array of int", then the declaration
typedef int (*blah)[N];
declares blah as an alias for the type "pointer to N-element array of int".
In the example you provide,
unsigned short int US;
declares US as object of type unsigned short int; thus,
typedef unsigned short int US;
declares US as an alias for the type unsigned short int.
Declarations (and thus typedefs) can get arbitrarily complex:
int *(*(*foo())[N])(double);
foo is a pointer to a function that returns a pointer to an array of pointers to functions taking a double parameter and returning a pointer to int. Adding a typedef:
typedef int *(*(*foo())[N])(double);
changes foo to be an alias for the type "function returning a pointer to an array of pointers to functions taking a double parameter and returning a pointer to int; again,
foo bar;
is equivalent to writing
int *(*(*bar())[N])(double);
int is not "altered" by a typedef. typedef unsigned short int US; is not "altering" unsigned short int, it is defining the identifier US to denote the same type as unsigned short int. Likewise, typedef int (*OP_TYPE)(int,int) is defining the identifier OP_TYPE to denote the same type as int (*)(int, int) (a pointer to a function returning int with parameter type list int, int).
Syntactically, typedef is like a storage class specifier but it defines a "typedef name" instead of declaring a variable. Compare typedef int (*OP_TYPE)(int, int); to static int (*op)(int, int);. OP_TYPE is a typedef name and op is a variable. OP_TYPE and op both have the same type int (*)(int, int). OP_TYPE can be used as a type in subsequent declarations, so that static OP_TYPE op; is equivalent to static int (*op)(int, int);
Welcome to stackoverflow #moveityourself01!
OP_TYPE is a function pointer type. Here is an example:
// This is a function
// It has a single parameter and returns
// an int
int some_func(int a) {
return(a+1);
}
int main(void) {
// regular usage of the function
printf("some_func(1) = %d\n", some_func(1));
// fun_ptr is a function pointer
// that points to the function some_func
int (*fun_ptr)(int) = &some_func;
printf("via fun_ptr->some_func(2) = %d\n", fun_ptr(2));
// create the typedef
typedef int (*funptr_type)(int);
// usage of typedef
funptr_type another_func_ptr = &some_func;
// usage of function pointer via typedef
printf("via typedef some_func(3) = %d\n", another_func_ptr(3));
return(0);
}
Usage
some_func(1) = 2
via fun_ptr->some_func(2) = 3
via typedef some_func(3) = 4

Casting functions

I have the following functions:
typedef int (*Bar)(void *, int a);
int foo (Struct *s, int b);
void *call(Bar c);
What does it mean when I call the function:
call( (Bar) foo);
typedef int (*Bar)(void *, int a);
This defines Bar an alias for a pointer-to-function type, specifically for a function that takes two arguments of type void* and int and returns a result of type int.
int foo (Struct *s, int b);
This declares (but does not define) a function named foo that takes two arguments as specified.
I presume Struct is a typedef, but it's a poor name, easily confused with the struct keyword.
void *call(Bar c);
This declares a function call that takes an argument of type Bar and returns a void* result.
call( (Bar) foo);
foo is the name of the function declared earlier. In this context, it's treated as an expression of pointer-to-function type. This pointer value is converted to type Bar. Since `Bar is a pointer-to-function type, the conversion is well defined.
That converted pointer is then passed to a function named call. (call returns a void* result, but it's quietly ignored here; is that what you intended?)
We don't know what the call function does with its argument, so we can't tell what the behavior of this statement might be.
A conversion from one function pointer type to another, using a cast, is well defined, and converting back to the original type will yield the original value. Calling a function using a function pointer with the wrong type has undefined behavior. (You might be able to get away with it in some cases, but don't.)
Your call function could try to make a call via its parameter, but that call would have undefined behavior unless that parameter is converted back to the correct type.
There isn't enough information in your question to know what's going on, and the confusing names you've chosen don't help.

What in the syntax rules makes prototypes of functions that return pointers and function pointers different?

The prototype for defining a function that returns a pointer looks like this:
int * function_name();
At the same time, the prototype for a function pointer looks like this:
int (*function_name)();
What syntax rules makes those two definitions different? How does precedence come into play?
For instance, is
(int *) function_name();
a prototype for a function that returns a pointer or a pointer function? (My intuition is that it defines a function that return (int *), and hence is the former.)
Edit: I realized that my question is actually about C declarations. A good resource for understanding those is http://unixwiz.net/techtips/reading-cdecl.html
What syntax rules makes those two definitions different?
The rule for parsing is:
Locate the identifier.
Always favour [] and () over *.
So, for int * function_name();, identifier function_name will goes with () instead of * and therefore function_name is declared as function that returns pointer to int.
For int (*function_name)();, The extra outer parenthesis force function_name to comes with * rather than (). So, this declares function_name as a pointer to function that returns an int.
(int *) function_name(); can't be used outside of a function. Compiler will report a syntax error. Upon seeing (int *) compiler will interpret is as a cast operator and function_name() as a function call.
Further reading: Deciphering complex declaration like void ( *( *f[] ) () ) ().
(int *) function_name();
as a function prototype is syntax error.
When calling function_name(); that way, it casts the return value to an int *:
int main(void) {
(int *) function_name(); //the return value is being casted to an `int *`
return 0;
}
The following is a function that returns a pointer:
int *function_name();
And the following is a function pointer, i.e. a pointer to a function:
int (*function_name)();
Let me cite this:
Sometimes people get confused when more stars are thrown in:
void *(*foo)(int *);
Here, the key is to read inside-out; notice that the innermost element of the expression is *foo, and that otherwise it looks like a normal function declaration. *foo should refer to a function that returns a void * and takes an int *. Consequently, foo is a pointer to just such a function.
OK, so applying the rules of reading C declarations (e.g. here):
int * function_name();
declares function_name as a function returning a pointer to int, whereas
int (* function_name)();
declares function_name as a pointer to a function returning int.

Can someone explain why "void func_dec(void (*)(int) funcptr);" is illegal

When declaring a functions which takes function pointer as argument as mentioned below the compiler throws error.
void func_dec(int x, void(*)() funcptr);
Whereas it accepts below declaration,
void func_dec(int x, void(*funcptr)());
Why the compiler could not recognize the former declaration though it looks logical.
It is illegal because the formal definition in the language standard says so. As for the reason why it is that way, and it really may seem obscure, here it is:
From The New C Standard: An Economic and Cultural Commentary (v 1.2 from June 24, 2009, section 6.7 Declarations):
The intent of this syntax is for an identifier’s declarator to have
the same visual appearance as an instance of that identifier in an
expression. For instance, in:
int x[3], *y, z(void);
char (*f(int))[];
the identifier x might appear in the source as an indexed
array, y as a dereferenced pointer, and z as a function call. An
example of an expression using the result of a call to f is
(*f(42))[1].
And the same from The Development of the C Language by Dennis M. Ritchie:
Thus,
int i, *pi, **ppi;
declare an integer, a pointer to an integer, a
pointer to a pointer to an integer. The syntax of these declarations
reflects the observation that i, *pi, and **ppi all yield an int type
when used in an expression. Similarly,
int f(), *f(), (*f)();
declare
a function returning an integer, a function returning a pointer to an
integer, a pointer to a function returning an integer;
int *api[10], (*pai)[10];
declare an array of pointers to integers, and a pointer to
an array of integers. In all these cases the declaration of a variable
resembles its usage in an expression whose type is the one named at
the head of the declaration.
This is because,
void(*)() funcptr
is in invalid syntax on it's own.
Just supply the type while writing the function declaration,
void func_dec(int , void(*) ());
it should be enough. Otherwise, if you want to specify the variable name also, write
void func_dec(int x, void(*funcptr) ());
The function parameter name should go in the same place as the function name goes when you declare a function.
Function declaration:
void func(); // correct syntax
void() func; // incorrrect syntax
Function pointer declaration:
void (*func_ptr)(); // correct syntax
void (*)() func_ptr; // incorrect syntax
Declaring a function pointer becomes easier if you use the following trick:
Take the function declaration. Replace the function name with (*pointerName), or (*) if you want an unnamed version.
Example:
int func1(char* parm1); // function
int (*func1_ptr)(char* parm1); // function pointer
// function taking a function pointer as parameter:
void foo(int (*func1_ptr)(char*));
// The same declaration with an unnamed parameter:
void foo(int (*)(char*));

C defining function pointer with pointer agruments

I'm trying to understand what's wrong with:
typedef *void (*pfun)(**int, *float);
as far as I understand the problem is that I can't pass the function the pointers as
typedef *void (*pfun)(int, float);
doesn't generate an error but I have no idea why that is the case.
Did you mean void* , int** and float*?
You are not using valid C/C++ syntax for pointer declaration in the following expression:
typedef *void ( *pfun )( **int, *float );
Recall: Points are declared in the following format:
datatype *identifier
... and hence your type definition should be written as:
typedef void* (*pfun)( int**, float* );
Remark: Spacing does not matter when declaring pointers, hence the following are equivalent:
datatype *identifier
datatype* identifier
... however you will find that most programers agree that it is a good practice to do the first pointer declaration as it communicates that the identifier is a pointer to a data type. This practice becomes more apparently useful when declaring multiple pointer on one line. Example:
int *ptr1, *ptr2, *ptr3; // Declaring 3, valid, pointers to integers.
int* ptr1, ptr2, ptr3; // Declares 1, valid, pointer to an integer and 2 other integers.
This is a good question for new programmers. The de-reference operator has several uses in defining pointers.
First, it can be placed BEFORE a variable name. This implies that the variable is a pointer to a data type, such as: int *X; means that X points to RAM which contains an integer value.
Second, it can appear to stand alone as part of a cast statement: (int *) Y which means that the contents of Y are to be interpreted as a pointer to an integer.
Third, and probably its most obtuse usage is to indicate a pointer to a function. For example,
int (*func_ptr_ret_int)(void);
Declares to C that the variable func_ptr_ret_int points to a function that does NOT take any parameters and returns an integer. In this example, func_ptr_ret_int has yet to be assigned a value and so it should be assumed to contain garbage.
A fourth usage, is to indicate a double pointer: int **Z; declares that Z points to a another pointer(un-named) which in turn points to an integer.
Finally, I would recommend that you defer using typedef statement until you can code a declaration "natively". That is, typedef only defines a new data type is does NOT allocate storage or assign values.
With this in mind your two statements could be coded as:
void (*pfun1)(int **, float *); // pfun1 points to a function that returns void
// and uses a double ptr to inf and ptr to float
void *(*pfun2)(int, float); // pfun2 points to a function that returns a void
// pointer and accepts int and float parameters.
Hope this helps.
typedef void* (*pfun)(int **i, float f); This means function pointer which has int * , float * as arguments and returns void *. But in your post the dereference operator is not in proper place.

Resources