8

A friend of mine was trying to test me on C (my strongest language is C++) and he asked me three questions which I could not answer:

Try to explain the following declarations:

1) int (*x)(int, char *, void *);
2) int (*x[10])(int, char *, void *);
3) int (**x[10])(int, char *, void *);

Can anyone explain these function declarations and explain what concepts are being used?

nmuntz
  • 1,158
  • 2
  • 11
  • 22

5 Answers5

32

You need the cdecl program, which will give you a definite, correct answer to such questions. Learning to interpret such statements manually is doable and beneficial, but even so cdecl is extremely useful for checking if you have an correct answer.

prompt>cdecl
Type `help' or `?' for help
cdecl> explain int (*x)(int, char *, void *);
declare x as pointer to function (int, pointer to char, pointer to void) returning int
cdecl> explain int (*x[10])(int, char *, void *);
declare x as array 10 of pointer to function (int, pointer to char, pointer to void) returning int
cdecl> explain int (**x[10])(int, char *, void *);
declare x as array 10 of pointer to pointer to function (int, pointer to char, pointer to void) returning int
cdecl>
hlovdal
  • 26,565
  • 10
  • 94
  • 165
21

Well, the first one is a pointer to a function. In other words, it declares a variable "x" which points to a function of the following type:

int function(int, char*, void*);

And could be used as follows:

int myfunc(int a, char* b, void* c) {
    return a;
}

void acallingfunction() {
    int (*x)(int, char*, void*);
    x = myfunc;
    x(1, "hello", 0);
}

The second appears to be invalid syntax, but I may be wrong. If it had an asterisk before the x (such as int (*x[10])(int, char*, void*) ), it would be an array of function pointers, and would be used like a normal array:

x[3](1, "Hi there", 0);

The third is an array of pointers to function pointers, which doesn't seem practical, but is perfectly valid. An example usage might be:

void anothercaller() {
    int (*x)(int, char*, void*);
    int (**y)(int, char*, void*);
    x = myfunc;
    y = &x;
    (*y)(1, "hello", 0);
}

Note that of these, the first two are relatively common. Pointers to functions are used to accomplish callbacks and various Object-Oriented programming concepts in C. An array of pointers to functions might be used for an event table, to find the appropriate callback.

Note that all of those are, in fact, valid C++ as well. ;)

Edit: I committed the atrocities of void main() apparently.

Edit 2: As Chris Lutz points out below, they really should be wrapped in typedefs. Typedefs make code containing pointers to functions MUCH clearer.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
Walt W
  • 3,261
  • 3
  • 30
  • 37
7
  1. A function pointer
  2. An array of function pointers
  3. An array of pointers to function pointers
tensaix2j
  • 462
  • 6
  • 18
  • 1
    Actually, the second one is an array of functions, not function pointers, and is a syntax error according to GCC: `:1: error: declaration of ‘x’ as array of functions` – Chris Lutz Aug 26 '09 at 01:41
6

They are function pointers, as said above, but written rather obnoxiously (in my opinion). The way I would write them is:

typedef int (*funcptr)(int, char *, void *);

funcptr x;
funcptr x[10];
funcptr *x;

See Walt W's excellent answer for more about function pointers.

Community
  • 1
  • 1
Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
3

Since the syntax of C is like the one of C++ in this matter, geordi could be interesting to you. It is another good tool for teaching and learning those declarations (and other things related to C++ and sometimes, C too).

geordi: << ETYPE_DESC(x); int (*x)(int, char *, void *);
lvalue pointer to a function taking an integer, a pointer to a character, a pointer to anything, and returning an integer

geordi: << ETYPE_DESC(x); int (*x[10])(int, char *, void *);
lvalue array of 10 pointers to functions taking an integer, a pointer to a character, a pointer to anything, and returning integers

geordi: << ETYPE_DESC(x); int (**x[10])(int, char *, void *);
lvalue array of 10 pointers to pointers to functions taking an integer, a pointer to a character, a pointer to anything, and returning integers

As its page explains, it can do much more, including building a type for you

geordi: make type array of 10 pointers to functions taking an integer and returning void
void(*[10])(int)

If you know in principle how to declare things, but are unsure about just one thing, you may use parentheses:

geordi: make type ( void(int, bool) )*
void(*)(int, bool)

If you want to see how this looks like with an identifier in it, you may change the type of names, too

geordi: -c int x;
Success
geordi: make x a ( void(int, bool) )* and show
-c void (* x)(int, bool) ;

If you build up a declaration, but you are unsure about the precedence of the operators, then geordi's precedence functions can help you out

geordi: precedence *x(a, b)
*(x(a, b))
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212