prev up next   top/contents search

comp.lang.c FAQ list · Question 1.21

Q: How do I construct declarations of complicated types such as ``array of N pointers to functions returning pointers to functions returning pointers to char'', or figure out what similarly complicated declarations mean?


A: The first part of this question can be answered in at least three ways:

  1. char *(*(*a[N])())();
  2. Build the declaration up incrementally, using typedefs:
    	typedef char *pc;	/* pointer to char */
    	typedef pc fpc();	/* function returning pointer to char */
    	typedef fpc *pfpc;	/* pointer to above */
    	typedef pfpc fpfpc();	/* function returning... */
    	typedef fpfpc *pfpfpc;	/* pointer to... */
    	pfpfpc a[N];		/* array of... */
    
  3. Use the cdecl program, which turns English into C and vice versa. You provide a longhand description of the type you want, and cdecl responds with the equivalent C declaration:
    	cdecl> declare a as array of pointer to function returning
    		pointer to function returning pointer to char
    
    	char *(*(*a[])())()
    
    cdecl can also explain complicated declarations (you give it a complicated declaration and it responds with an English description), help with casts, and indicate which set of parentheses the parameters go in (for complicated function definitions, like the one above). See question 18.1.

C's declarations can be confusing because they come in two parts: a base type, and a declarator which contains the identifier or name being declared, perhaps along with *'s and []'s and ()'s saying whether the name is a pointer to, array of, or function returning the base type, or some combination.[footnote] For example, in

	char *pc;
the base type is char, the identifier is pc, and the declarator is *pc; this tells us that *pc is a char (this is what ``declaration mimics use'' means).

One way to make sense of complicated C declarations is by reading them ``inside out,'' remembering that [] and () bind more tightly than *. For example, given

	char *(*pfpc)();
we can see that pfpc is a pointer (the inner *) to a function (the ()) to a pointer (the outer *) to char. When we later use pfpc, the expression *(*pfpc)() (the value pointed to by the return value of a function pointed to by pfpc) will be a char.

Another way of analyzing these declarations is to decompose the declarator while composing the description, maintaining the ``declaration mimics use'' relationship:

	*(*pfpc)()	is a	char
	(*pfpc)()	is a	pointer to char
	(*pfpc)	is a	function returning pointer to char
	pfpc	is a	pointer to function returning pointer to char

If you'd like to make things clearer when declaring complicated types like these, you can make the analysis explicit by using a chain of typedefs as in option 2 above.

The pointer-to-function declarations in the examples above have not included parameter type information. When the parameters have complicated types, declarations can really get messy. (Modern versions of cdecl can help here, too.)

Additional links:

A message of mine explaining the difference between array-of-pointer vs. pointer-to-array declarations

David Anderson's ``Clockwise/Spiral Rule''

References: K&R2 Sec. 5.12 p. 122
ISO Sec. 6.5ff (esp. Sec. 6.5.4)
H&S Sec. 4.5 pp. 85-92, Sec. 5.10.1 pp. 149-50


prev up next   contents search
about this FAQ list   about eskimo   search   feedback   copyright

Hosted by Eskimo North