SpiderTerm Lecture 1

CS1000 Home
Lab 1

ajdavis home

C Declarations

lecture-1 draft 0.12 25-june-2000

The business side is easy—easy! ...if you're any good at math at all, you understand business. It's not its own deep, deep subject. It's not like C++.
               —Bill Gates, Upside Magazine, April 1992

Sorry for the lateness of this lab and lecture. When you hit the Lab 1 link on the left, you'll see that I've given you some extra time on this one. In general, my lecture notes and the corresponding lab will be online at least a day before Monday's lecture.

So this week's lecture was kind of a dud. In the future I'll know to have more thorough lecture notes, to throw things at Antonio and Heather, and not to try to do class right after hearing some alum read lists for two hours.

To give you a better background for the lab, I've excerpted from Peter van der Linden's Expert C Programming:

The Precedence Rule

We have now reviewed the building blocks of declarations. This section describes one method for breaking them down into an English explanation. The precedence rule for understanding C declarations is the one that the language lawyers like best. It's high on brevity, but very low on intuition.

The Precedence Rule for Understanding C Declarations

A -- Declarations are read by starting with the name and then reading in precedence order.
B -- The precedence, from high to low, is:
B.1 -- parentheses grouping together parts of a declaration
B.2 -- the postfix operators:
parentheses ( ) indicating a function, and
square brackets [ ] indicating an array.
B.3 -- the prefix operator: the asterisk denoting "pointer to".
C -- If a const and/or volatile keyword is next to a type specifier (e.g. int, long, etc.) it applies to the type specifier. Otherwise the const and/or volatile keyword applies to the pointer asterisk on its immediate left.

Solving a Declaration Using the Precedence Rule

An example of solving a declaration using the Precedence Rule:

char * const *(*next)();

(Rule to apply followed by explanation)
A -- First, go to the variable name, "next", and note that it is directly enclosed by parentheses.
B.1 -- So we group it with what else is in the parentheses, to get "next is a pointer to..."
B -- Then we go outside the parentheses, and have a choice of a prefix asterisk, or a postfix pair of parentheses.
B.2 -- Rule B.2 tells us the highest precedence thing is the function parentheses at the right, so we have "next is a pointer to a function returning-"
B.3 -- Then process the prefix "*" to get "pointer to".
C -- Finally, take the "char * const", as a constant pointer to a character.

Then put it all together to read:

"next is a pointer to a function returning a pointer to a const pointer-to-char"

and we're done. The precedence rule is what all the rules boil down to, but if you prefer something a little more intuitive, click here.


Unscrambling C Declarations by Diagram

In this section we present a diagram with numbered steps (see Figure3-3). If you proceed in steps, starting at one and following the guide arrows, a C declaration of arbitrary complexity can quickly be translated into English (also of arbitrary complexity). We'll simplify declarations by ignoring typedefs in the diagram. To read a typedef, translate the declaration ignoring the word "typedef". If it translates to "p is a-", you can now use the name "p" whenever you want to declare something of the type to which it translates. Let's try a couple of examples of unscrambling a declaration using the diagram. Say we want to figure out what our first example of code means:

char * const *(*next)();

As we unscramble this declaration, we gradually "white out" the pieces of it that we have already dealt with, so that we can see exactly how much remains. Again, remember const means "read-only". Just because it says constant, it doesn't necessarily mean constant.

The process is represented in the table below. In each step, the portion of the declaration we are dealing with is printed in bold type. Starting at step one, we will proceed through these steps.

Steps in Unscrambling a C Declaration

Declaration Remaining
(start at leftmost identifier)
Next Step to Apply Result
char * const *(*next) (); step 1 say "next is a ..."
char * const *(*_ _ _ _ ) (); step 2, 3 doesn't match, go to next step, say "next is a ..."
char * const *(*_ _ _ _ ) (); step 4 doesn't match, go to next step
char * const *(*_ _ _ _ ) (); step 5 asterisk matches, say "pointer to ...", go to step 4
char * const *(_ _ _ _ _) (); step 4 "(" matches up to ")", go to step 2
char * const * _ _ _ _ _ _ _ (); step 2 doesn't match, go to next step
char * const * _ _ _ _ _ _ (); step 3 say "function returning ..."
char * const * _ _ _ _ _ _ _  _ _; step 4 doesn't match, go to next step
char * const * _ _ _ _ _ _ _  _ _ ; step 5 say "pointer to ..."
char * const _ _ _ _ _ _ _  _ _; step 5 say "read-only ..."
char *_ _ _ _ _   _ _ _ _ _ _ _ _ ; step 5 say "pointer to ..."
char _ _ _ _ _ _ _ _ _  _ _; step 6 say "char"
Then put it all together to read:

"next is a pointer to a function returning a pointer to a read-only pointer-to-char"

and we're done.

Examples from class

Now try the example in class:

void (*signal(int signum, void (*handler)(int)))(int);

If you like, do "man signal" to see what signal actually does. Note, too, that the declaration could have been made worse by saying:

void (*signal(int, void (*)(int)))(int);

Or better by saying:

typedef void (*sig_handler)(int);
sig_handler signal(int, sig_handler);