int (*clever1(int (* (*goo_ptr)(int, int, int (*)(int, int), int(*)(int, int)))(int, int), int a, int b, int (*a_fptr)(int, int), int(*b_fptr)(int, int) ))(int, int) {
return goo_ptr(a,b,b_fptr,a_fptr);
}
what is type of clever1? what is type of goo_ptr? I can't understand the code.
clever1 is a function that returns a pointer to a function. The returned function returns an int and takes two ints as arguments.
clever1 function takes 5 arguments - goo_ptr, a, b, b_fptr and a_fptr.
goo_ptr is a pointer to a function that returns a pointer to a function. That returned function returns an int and takes two ints as arguments. goo_ptr points to a function that takes 4 arguments. The first two arguments have type int, the last two are pointers to functions that return an int and take two arguments of the same type int.
a and b are both just ints.
a_fptr and b_fptr are both pointers to functions returning int and taking two ints as arguments.
Looks like a common theme here - take two ints return an int.
Related
I have been attempting C recently and have been reading C source code,
however I came across this perculiar method signature with a * beside its name,
can someone explain this to me please
int *bubble_sort(int *numbers, int count, compare_cb cmp)
edit: I am referring to the * infront of bubble_sort
The asterisk has nothing to do with the function signature, it's just C's way of declaring pointers. The asterisk belongs to the type on the left, i.e. the return type for the function is int *, which is read out as "pointer to integer". The first argument has the exact same type, pointer to integer. You use this syntax everywhere in C, not just with function declarations.
The '*', used in this way, indicates that the 'bubble_sort()' function returns an address of (in other words, 'a pointer to) an integer, rather than an integer.
This concept is of pointers.
To know more about pointers see this link : http://www.tutorialspoint.com/cprogramming/c_pointers.htm
int *bubble_sort(int *numbers, int count, compare_cb cmp)
int *bubble_sort means that you are going to return the address of the integer,
and int *numbers means that you are getting the address of the variable as argument.
int a() is a function returning an int.
int * a() is a function returning a pointer to an int.
in your case the function returns a pointer to an integer.
guessing from the function name it is returning the sorted array.
an array in C is notated as a pointer to the first element:
int a[5];
int *b=a;
a and b are the same
However I guess you still have to do some more research on pointers which is not as complicated.
Perhaps this links might help: Pointer Primer
I am attempting to understand the underlying mechanics of how C handles complex typedefs, from a syntax perspective.
Consider the following examples below (references included at end of the question).
typedef int (*p1d)[10];
is the proper declaration, i.e. p1d here is a pointer to an array of
10 integers just as it was under the declaration using the Array type.
Note that this is different from
typedef int *p1d[10];
which would make p1d the name of an array of 10 pointers to type int.
So, if I consider operator precedence for both examples (I'll rewrite them):
int *p1d[10]; // Becomes ...
int* p1d[10];
So, reading left-to-right, and using operator precedence, I get: "Pointer to type int, named p1d, of size 10", which is wrong. As for the other/first case:
int (*p1d)[10];
Which I read as "p1d is a pointer, of type int, and is an array of 10 such elements", which is also wrong.
Could someone explain the rules applied for determining these typedefs? I would like to apply them to function pointers as well, and I'm hoping this discussion will also explain the logic behind const casts (ie: pointer to constant data vs const pointer to variable data).
Thank you.
References:
C Tutorial: Pointers to Arrays: http://www.taranets.net/cgi/ts/1.37/ts.ws.pl?w=329;b=285
Operator Precedence: http://www.swansontec.com/sopc.html
One of my professors wrote this little guide to reading these kinds of declarations. Give it a read, it'll be worth your while and hopefully answer any questions.
All credit goes to Rick Ord (http://cseweb.ucsd.edu/~ricko/)
The "right-left" rule is a completely regular rule for deciphering C
declarations. It can also be useful in creating them.
First, symbols. Read
* as "pointer to" - always on the left side
[] as "array of" - always on the right side
() as "function returning" - always on the right side
as you encounter them in the declaration.
STEP 1
------
Find the identifier. This is your starting point. Then say to yourself,
"identifier is." You've started your declaration.
STEP 2
------
Look at the symbols on the right of the identifier. If, say, you find "()"
there, then you know that this is the declaration for a function. So you
would then have "identifier is function returning". Or if you found a
"[]" there, you would say "identifier is array of". Continue right until
you run out of symbols *OR* hit a *right* parenthesis ")". (If you hit a
left parenthesis, that's the beginning of a () symbol, even if there
is stuff in between the parentheses. More on that below.)
STEP 3
------
Look at the symbols to the left of the identifier. If it is not one of our
symbols above (say, something like "int"), just say it. Otherwise, translate
it into English using that table above. Keep going left until you run out of
symbols *OR* hit a *left* parenthesis "(".
Now repeat steps 2 and 3 until you've formed your declaration. Here are some
examples:
int *p[];
1) Find identifier. int *p[];
^
"p is"
2) Move right until out of symbols or right parenthesis hit.
int *p[];
^^
"p is array of"
3) Can't move right anymore (out of symbols), so move left and find:
int *p[];
^
"p is array of pointer to"
4) Keep going left and find:
int *p[];
^^^
"p is array of pointer to int".
(or "p is an array where each element is of type pointer to int")
Another example:
int *(*func())();
1) Find the identifier. int *(*func())();
^^^^
"func is"
2) Move right. int *(*func())();
^^
"func is function returning"
3) Can't move right anymore because of the right parenthesis, so move left.
int *(*func())();
^
"func is function returning pointer to"
4) Can't move left anymore because of the left parenthesis, so keep going
right. int *(*func())();
^^
"func is function returning pointer to function returning"
5) Can't move right anymore because we're out of symbols, so go left.
int *(*func())();
^
"func is function returning pointer to function returning pointer to"
6) And finally, keep going left, because there's nothing left on the right.
int *(*func())();
^^^
"func is function returning pointer to function returning pointer to int".
As you can see, this rule can be quite useful. You can also use it to
sanity check yourself while you are creating declarations, and to give
you a hint about where to put the next symbol and whether parentheses
are required.
Some declarations look much more complicated than they are due to array
sizes and argument lists in prototype form. If you see "[3]", that's
read as "array (size 3) of...". If you see "(char *,int)" that's read
as "function expecting (char *,int) and returning...". Here's a fun
one:
int (*(*fun_one)(char *,double))[9][20];
I won't go through each of the steps to decipher this one.
Ok. It's:
"fun_one is pointer to function expecting (char *,double) and
returning pointer to array (size 9) of array (size 20) of int."
As you can see, it's not as complicated if you get rid of the array sizes
and argument lists:
int (*(*fun_one)())[][];
You can decipher it that way, and then put in the array sizes and argument
lists later.
Some final words:
It is quite possible to make illegal declarations using this rule,
so some knowledge of what's legal in C is necessary. For instance,
if the above had been:
int *((*fun_one)())[][];
it would have been "fun_one is pointer to function returning array of array of
^^^^^^^^^^^^^^^^^^^^^^^^
pointer to int". Since a function cannot return an array, but only a
pointer to an array, that declaration is illegal.
Illegal combinations include:
[]() - cannot have an array of functions
()() - cannot have a function that returns a function
()[] - cannot have a function that returns an array
In all the above cases, you would need a set of parens to bind a *
symbol on the left between these () and [] right-side symbols in order
for the declaration to be legal.
Here are some legal and illegal examples:
int i; an int
int *p; an int pointer (ptr to an int)
int a[]; an array of ints
int f(); a function returning an int
int **pp; a pointer to an int pointer (ptr to a ptr to an int)
int (*pa)[]; a pointer to an array of ints
int (*pf)(); a pointer to a function returning an int
int *ap[]; an array of int pointers (array of ptrs to ints)
int aa[][]; an array of arrays of ints
int af[](); an array of functions returning an int (ILLEGAL)
int *fp(); a function returning an int pointer
int fa()[]; a function returning an array of ints (ILLEGAL)
int ff()(); a function returning a function returning an int
(ILLEGAL)
int ***ppp; a pointer to a pointer to an int pointer
int (**ppa)[]; a pointer to a pointer to an array of ints
int (**ppf)(); a pointer to a pointer to a function returning an int
int *(*pap)[]; a pointer to an array of int pointers
int (*paa)[][]; a pointer to an array of arrays of ints
int (*paf)[](); a pointer to a an array of functions returning an int
(ILLEGAL)
int *(*pfp)(); a pointer to a function returning an int pointer
int (*pfa)()[]; a pointer to a function returning an array of ints
(ILLEGAL)
int (*pff)()(); a pointer to a function returning a function
returning an int (ILLEGAL)
int **app[]; an array of pointers to int pointers
int (*apa[])[]; an array of pointers to arrays of ints
int (*apf[])(); an array of pointers to functions returning an int
int *aap[][]; an array of arrays of int pointers
int aaa[][][]; an array of arrays of arrays of ints
int aaf[][](); an array of arrays of functions returning an int
(ILLEGAL)
int *afp[](); an array of functions returning int pointers (ILLEGAL)
int afa[]()[]; an array of functions returning an array of ints
(ILLEGAL)
int aff[]()(); an array of functions returning functions
returning an int (ILLEGAL)
int **fpp(); a function returning a pointer to an int pointer
int (*fpa())[]; a function returning a pointer to an array of ints
int (*fpf())(); a function returning a pointer to a function
returning an int
int *fap()[]; a function returning an array of int pointers (ILLEGAL)
int faa()[][]; a function returning an array of arrays of ints
(ILLEGAL)
int faf()[](); a function returning an array of functions
returning an int (ILLEGAL)
int *ffp()(); a function returning a function
returning an int pointer (ILLEGAL)
Simplfying KepaniHaole's rules a bit, it boils down to:
Find the left-most identifer
Work your way out, remembering that absent explicit grouping by parentheses, function-call () and [] bind before *.
Apply recursively to any function parameters.
Thus, T *a[] is an array of pointer tp T, T (*a)[] is a pointer to an array of T, T *f() is a function returning a pointer to T, , and T (*f)() is a pointer to a function returning T.
Taking an example that gives a lot of people heartburn, we can look at the prototype for the POSIX signal function:
void (*signal( int sig, void (*func)( int )))( int );
which reads as
signal -- signal
signal( ) -- is a function with
signal( sig ) -- parameter sig
signal( int sig ) -- of type int
signal( int sig, func ) -- and parameter func
signal( int sig, (*func) ) -- of type pointer to
signal( int sig, (*func)( )) -- a function with
signal( int sig, (*func)( int )) -- an int parameter
signal( int sig, void (*func)( int )) -- returning void
(*signal( int sig, void (*func)( int ))) -- returning a pointer to
(*signal( int sig, void (*func)( int )))( ) -- a function with
(*signal( int sig, void (*func)( int )))( int ) -- an int parameter
void (*signal( int sig, void (*func)( int )))( int ) -- returning void
int (*(*q)(int (*)()))();
Ok, I start with: q is a pointer to a function, which takes... Not sure what should follow next, but perhaps it's ...a pointer to function, which takes nothing and returns int, and returns pointer to a function, which takes nothing and returns int.
The trick is that q itself is a function pointer that returns and takes a function pointer. cdecl says:
declare q as pointer to function (pointer to function returning int) returning pointer to function returning int
Find the lefmost identifier, then work your way out remembering that *a[] is an array of pointer, (*a)[] is a pointer to an array, *f() is a function returning a pointer, and (*f)() is a pointer to a function. Remember that in a prototype you only need to provide the type of the parameter; int f( int ); declares f as a function that takes a single int parameter; int f( int * ); declares f as a function that takes a single int pointer as a parameter. Similarly, int f( int (*)[N] ); declares f as a function that takes a pointer to an array as a parameter. Apply these rules recursively to any parameters in the function.
Thus:
q -- q
*q -- is a pointer to
(*q)( ) -- a function
(*q)( * ) -- that takes a pointer to
(*q)( (*)()) -- a function
(*q)(int (*)()) -- returning int
*(*q)(int (*)()) -- returning a pointer to
(*(*q)(int (*)()))() -- a function
int (*(*q)(int (*)()))(); -- returning int
You are right.
q is a pointer point to a function passing an pointer to a function (passing nothing returning int) returning a pointer to a function (passing nothing returning int).
See here.
http://c-faq.com/decl/spiral.anderson.html
According to Precedence and associativity of Operators in the C Programming language.
You can understand it in the following steps:
int (*(*q)(int (*)()))();
q->*->(int (*)())->*->()->int
1 2 3 4 5
1:q is a pointer
2:q is a function pointer, the function it points to has a parameter int (*)(), which is also a function pointer, points to a function has no parameters and return type is int.
3:q is a function pointer, the function it pointers to has parameter int (*)(), which is also a function pointer, points to a function has no parameters and return type is int. And
the function which q points to has a return type : pointer.
4:q is a function pointer, the function it pointers to has parameter int (*)(), which is also a function pointer, points to a function has no parameters and return type is int. And
the function which q points to has a return type : pointer(this pointer also points to a function which has no parameter).
5:q is a function pointer, the function it pointers to has parameter int (*)(), which is also a function pointer, points to a function has no parameters and return type is int. And
the function which q points to has a return type : pointer(this pointer also points to a function which has no parameter and the function's return type is int).
I am certain q in int q[6][4] is of type (**q)[4], ie, pointer to a pointer to an integer array sized 4. But the book I have (I find it dubious!!) says that the int q[][4] part in the function definition void foo(int q[][4]){} is the same as int (*q)[4].I am ambivalent about the book, yet let me present for your consideration some issues that crop up in my mind over this.Your detailed explanation is very much sought.
1) During declaration,is the type of q in int q[][4] the same as in int q[6][4]? Contrary to what the book says, I see q[][4] as nothing but q[0][4] and I feel q is of type (**q)[4],and not (*q)[4].Am I right?What's your take on it?
2) (Most confusing bit) I know passing int *q and int q[] (or int q[4]) is the same in C as the latter reduces to the former.But I have verified from the compiler that int (*q)[5] is not the same type as int (*q)[4], so what is the difference between passing as arguments to a function A) int (*q)[] B)int (*q)[4] and C)int (*q)[5] ? Please be detailed for the answer to this part.
3) How is passing int q[][4] to a function different from passing int q[6][4] in C?Does q reduce to (**q)[4] in both cases?
I am certain q in int q[6][4] is of type (**q)[4], ie, pointer to a pointer to an integer array sized 4
No. (The pointer-to-pointer-to-array is very, very far from the truth, specifically.) q is of type int[6][4], i. e. an array of 6 arrays of 4 integers.
When passed to a function, it's only the first (innermost) dimension of an array that decays into a pointer. So, int[6][4] decays into int (*)[4], and so does int[][4].
int (*q)[5] is not the same type as int (*q)[4], so what is the difference between passing as arguments to a function A) int (*q)[] B) int (*q)[4] and C) int (*q)[5]
A) is an incomplete type (pointer to array of any size). You can't dereference it, nor can you perform pointer arithmetic on it.
B) is a pointer to array of 4 ints. C) is a pointer to array of 5 ints.
How is passing int q[][4] to a function different from passing int q[6][4] in C?
Semantically, they mean the same. They both decay into int (*)[4].
Does q reduce to (**q)[4] in both cases?
No, but I've already explained that.
For the first question, q is an array of array of four integers.
You might want to read about the Clockwise/Spiral Rule. It might actually help you with the second question.
1) During declaration,is the type of q in int q[][4] the same as in
int q[6][4]?
Yes. The first dimension is not needed in a function declaration and a multidimensional array in a function declaration has type pointer to an array.
what is the difference between passing as arguments to a function A)
int (*q)[] B)int (*q)[4] and C)int (*q)[5] ?
int (*q)[] is a pointer to an array of unknown size. int (*q)[4] is a pointer to int[4] and int (*q)[5] is a pointer to int[5]. They all have different types.
3) How is passing int q[][4] to a function different from passing int
q[6][4] in C?Does q reduce to (**q)[4] in both cases?
They are both equivalent to int (*q)[4].
Pleas read 23.1: Multidimensional Arrays and Functions of the c.faq for more details.
I have a variadic function which takes a float parameter. Why doesn't it work?
va_arg(arg, float)
Parameters of functions that correspond to ... are promoted before passing to your variadic function. char and short are promoted to int, float is promoted to double, etc.
6.5.2.2.7 The ellipsis notation in a function prototype declarator causes
argument type conversion to stop after the last declared parameter. The default argument
promotions are performed on trailing arguments.
The reason for this is that early versions of C did not have function prototypes; parameter types were declared at the function site but were not known at the call site. But different types are represented differently, and the representation of the passed argument must match the called function's expectation. So that char and short values could be passed to functions with int parameters, or float values could be passed to functions with double parameters, the compiler "promoted" the smaller types to be of the larger type. This behavior is still seen when the type of the parameter is not known at the call site -- namely, for variadic functions or functions declared without a prototype (e.g., int foo();).
As #dasblinkenlight has mentioned, float is promoted to double.
It works fine for me:
#include <stdio.h>
#include <stdarg.h>
void foo(int n, ...)
{
va_list vl;
va_start(vl, n);
int c;
double val;
for(c = 0; c < n; c++) {
val = va_arg(vl, double);
printf("%f\n", val);
}
va_end(vl);
}
int main(void)
{
foo(2, 3.3f, 4.4f);
return 0;
}
Output:
3.300000
4.400000