Here is a silly puzzle I solved exactly one month ago.

Without using typedef, declare a pointer to a function which has an array of 10 pointers to functions which have int * argument and return type void as argument, and returns a pointer to a function which has int * argument and return type void.

If the above problem statement is difficult to understand, here is the same problem expressed in terms of typedef.

Without using typedef, declare a pointer that is equivalent to the following declaration of x.

typedef void (*func_t)(int *);
func_t (*x)(func_t [10]);

I'll describe how I solve such problems. I start from the right end of the problem and work my way to the left most end defining each part one by one.

Let me start.

void x(int *)
A function which has int * argument and return type void.

void (*x)(int *)
Pointer to a function which has int * argument and return type void.

void (*x())(int *)
A function that returns a pointer to a function which has int * argument and return type void.

void (*x(void (*)(int *)))(int *)
A function which has a pointer to a function that has int * argument and return type void as argument, and returns a pointer to a function which has int * argument and return type void.

void (*x(void (*[10])(int *)))(int *)
A function which has an array of 10 pointers to functions that has int * argument and return type void as argument, and returns a pointer to a function which has int * argument and return type void.

void (*(*x)(void (*[10])(int *)))(int *)
A pointer to a function which has an array of 10 pointers to functions that has int * argument and return type void as argument, and returns a pointer to a function which has int * argument and return type void.

I verified the declaration with a short code.

#include <stdio.h>

/* A function which has int * argument and return type void. */
void g(int *a)
{
    printf("g(): a = %d\n", *a);
}

/* A function which has an array of 10 pointers to functions that has
 * int * argument and return type void as argument, and returns a
 * pointer to a function which has int * argument and return type void.
 */
void (*f(void (*a[10])(int *)))(int *)
{
    int i;
    for (i = 0; i < 10; i++)
        a[i](&i);
    return g;
}

int main()
{
    /* An array of 10 pointers to functions that has int * argument and
     * return type void. */
    void (*a[10])(int *) = {g, g, g, g, g, g, g, g, g, g};

    /* A pointer to the function which has an array of 10 pointers to
     * functions that has int * argument and return type void as
     * argument, and returns a pointer to a function which has int *
     * argument and return type void. */
    void (*(*x)(void (*[10])(int *)))(int *) = f;

    /* A pointer to a function that has int * argument and return type
     * void. */
    void (*y)(int *a) = x(a);

    int i = 10;
    y(&i);
    return 0;
}

Section 5.12 (Complicated Declarations) of the second edition of The C Programming Language by Brian W. Kernighan and Dennis M. Ritchie has some good examples of complicated declarations of pointers although they are less clumsy than the one in this blog post. Let me mention a couple of interesting ones from that section.

char (*(*x())[])()
x: function returning pointer to array[] of pointer to function returning char.

char (*(*x[3])())[5]
x: array[3] of pointer to function returning pointer to array[5] of char.

4 comments

Mandeep said:

Nice! The syntax on "returning" function pointers was a little tricky. Learnt that today! :)

Iouri said:

There is a website that you can use for that: http://cdecl.org/

It can take "declare x as pointer to function (array 10 of pointer to function (pointer to int) returning void) returning pointer to function (pointer to int) returning void" and give back

void (*(*x)(void (*[10])(int *)))(int *)

Michael said:

I wrote a simple C parser once, and found this page to be very helpful in understanding complex C declarators: http://msdn.microsoft.com/en-us/library/1x82y1z4.aspx

Peter Desnoyers said:

See R. P. Mody. 1992. "On understanding type declarations in C." SIGPLAN Not. 27, 6 (June 1992), 80-83.

It gives a short calculus for understanding pre-ANSI type declarations. Best quote from it: "We are now ready to tackle a famous horror — 'signal' of UNIX".

Post a comment

RSS