问题
I have heard of some methods, but none of them have stuck. Personally I try to avoid complex types in C and try to break them into component typedef.
I\'m now faced with maintaining some legacy code from a so called \'three star programmer\', and I\'m having a hard time reading some of the ***code[][].
How do you read complex C declarations?
回答1:
This article explains a relatively simple 7 rules which will let you read any C declaration, if you find yourself wanting or needing to do so manually: http://www.ericgiguere.com/articles/reading-c-declarations.html
- Find the identifier. This is your starting point. On a piece of paper, write "declare identifier as".
- Look to the right. If there is nothing there, or there is a right parenthesis ")", goto step 4.
You are now positioned either on an array (left bracket) or function (left parenthesis) descriptor. There may be a sequence of these, ending either with an unmatched right parenthesis or the end of the declarator (a semicolon or a "=" for initialization). For each such descriptor, reading from left to right:
- if an empty array "[]", write "array of"
- if an array with a size, write "array size of"
- if a function "()", write "function returning"
Stop at the unmatched parenthesis or the end of the declarator, whichever comes first.
- Return to the starting position and look to the left. If there is nothing there, or there is a left parenthesis "(", goto step 6.
- You are now positioned on a pointer descriptor, "*". There may be a sequence of these to the left, ending either with an unmatched left parenthesis "(" or the start of the declarator. Reading from right to left, for each pointer descriptor write "pointer to". Stop at the unmatched parenthesis or the start of the declarator, whichever is first.
- At this point you have either a parenthesized expression or the complete declarator. If you have a parenthesized expression, consider it as your new starting point and return to step 2.
- Write down the type specifier. Stop.
If you're fine with a tool, then I second the suggestion to use the program cdecl
: http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html
回答2:
I generally use what is sometimes called the 'right hand clockwise rule'. It goes like this:
- Start from the identifier.
- Go to the immediate right of it.
- Then move clockwise and come to the left hand side.
- Move clockwise and come to the right side.
- Do this as long as the declaration has not been parsed fully.
There's an additional meta-rule that has to be taken care of:
- If there are parentheses, complete each level of parentheses before moving out.
Here, 'going' and 'moving' somewhere means reading the symbol there. The rules for that are:
*
- pointer to()
- function returning(int, int)
- function taking two ints and returningint
,char
, etc. -int
,char
, etc.[]
- array of[10]
- array of ten- etc.
So, for example, int* (*xyz[10])(int*, char)
is read as:
xyz is an
array of ten
pointer to
function taking an int* and a char and returning
an int*
回答3:
One word: cdecl
Damnit, beaten by 15 seconds!
回答4:
Cdecl (and c++decl) is a program for encoding and decoding C (or C++) type declarations.
http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html
回答5:
Back when I was doing C, I made use of a program called "cdecl". It appears that it's in Ubuntu Linux in the cutils or cdecl package, and it's probably available elsewhere.
回答6:
There's also a Web-based version of cdecl which is pretty slick.
回答7:
cdecl offers a command line interface so let's give it a try:
cdecl> explain int ***c[][]
declare c as array of array of pointer to pointer to pointer to int
another example
explain int (*IMP)(ID,SEL)
declare IMP as pointer to function (ID, SEL) returning int
However there is a whole chapter about that in the book "C Deep Secrets", named "Unscrambling declarations in C.
回答8:
Common readability problems include function pointers and the fact that arrays are really pointers, and that multidimensional arrays are really single dimension arrays (which are really pointers). Hope that helps some.
In any case, whenever you do understand the declarations, maybe you can figure out a way to simplify them to make them more readable for the next guy.
回答9:
Automated solution is cdecl.
In general, you declare a variable the way you use it. For example, you dereference a pointer p as in:
char c = * p
you declare it in a similar looking way:
char * p;
Same goes for hairy function pointers. Let's declare f to be good old "pointer to function returning pointer to int," and an external declaration just to be funny. It's a pointer to a function, so we start with:
extern * f();
It returns a pointer to an int, so somewhere in front there there's
extern int * * f(); // XXX not quite yet
Now which is the correct associativity? I can never remember, so use some parenthesis.
extern (int *)(* f)();
Declare it the way you use it.
回答10:
Just came across an illuminating section in "The Development of the C Language":
For each object of such a composed type, there was already a way to mention the underlying object: index the array, call the function, use the indirection operator on the pointer. Analogical reasoning led to a declaration syntax for names mirroring that of the expression syntax in which the names typically appear. Thus,
int i, *pi, **ppi;
declare an integer, a pointer to an integer, a pointer to a pointer to an integer. The syntax of these declarations reflects the observation that i, *pi, and **ppi all yield an int type when used in an expression. Similarly,
int f(), *f(), (*f)();
declare a function returning an integer, a function returning a pointer to an integer, a pointer to a function returning an integer;
int *api[10], (*pai)[10];
declare an array of pointers to integers, and a pointer to an array of integers. In all these cases the declaration of a variable resembles its usage in an expression whose type is the one named at the head of the declaration.
来源:https://stackoverflow.com/questions/89056/how-do-you-read-c-declarations