拾遗笔记

c里的变量或函数或数组的声明的解析,先右后左法则

比如看到这样一个声明,你肯定头都大了.:

int *(*(*F())[])();

  • F is a function returning a pointer to an array of pointers to
    functions returning a pointer to int.

法则

1 先找到或变量或函数或数组(因为现在还不知道它倒底是什么,暂命名为id)的名称.比如此处的F
2 接下来,从F往右读,如果遇到
下面三种标专时的读法:

  • * as "pointer to" 指向..的指针
  • [] as "array of" 是…类型的数组
  • () as "function returning" 是一个返回..类型的函数

比如

  • F()

读作

  • F是一个返回(..类型)的函数,
  • F is a function returing …

类型我们还不知道.
当读完这个id,或者遇到右括号)时,开始沿id 往左读
比如接下来是

  • *F()
    读作
    • F是一个返回 ((指向..的指针) 类型)的函数, (1因为这个指针指向什么,还不清楚用..代替)
    • F is a function returing a pointer to …

遇到左括号,则返回继续向右读

  • (*F())[]

遇到)往左,又遇到(,变为往右,然后是[]:

  • F是一个返回(指向(..类型的数组)的指针)的函数,
  • F is a function returing a pointer to an array of…
  • (*(*F())[])
    • F是一个返回( 指向((指向..类型的指针) 类型的数组)的指针)的函数,
    • F is a function returing a pointer to an array of a pointer to …
  • (*(*F())[])()
  • F是一个返回 (指向 ((指向(返回..类型的函数)的指针) 类型的数组) 的指针) 的函数,
  • F is a function returing a pointer to an array of a pointer to a function returing ..
  • int *(*(*F())[])();
    • F是一个返回(指向 ((指向(返回(指向int的指针)类型的函数)指针) 类型的数组) 的指针) 的函数,
    • F is a function returing a pointer to an array of a pointer to a function returing a pointer to int

一些示例

int x;

  • x is an int.

int *x;

  • x is a pointer to an int.

int **x;

  • x is a pointer to a pointer to an int.

const int x;

  • x is a const int (constant integer).

const int *x;

  • x is a pointer to a const int. The value of x may change, but
    the integer that it points to not be changed. In other words,
    x cannot be used to alter the value to which it points.

int *const x;

  • x is a constant pointer to an int. The value may not change,
    but the integer that it points to may change. In other words,
    x will always point at the same location, but the contents may
    vary.

const int *const x;

  • x is a constant pointer to a constant integer. The value of x
    may not change, and the integer that it points to may not
    change. In other words, x will always point at the same
    location, which cannot be modified via x.

int x[];

  • x is an array of int.

int x[99 ];

  • x is an array of 99 int's.

int *x[];

  • x is an array of pointers to int.

int (*x)[];

  • x is a pointer to an array of int.

int *(*x)[];

  • x is a pointer to an array of pointers to int.

int F();

  • F is a function returning int.

int *F();

  • F is a function returning a pointer to int.

int (*x)();

  • x is a pointer to a function returning int.

int (*x[ 99])();

  • x is an array of 99 pointers to functions returning int.

int (*F())();

  • F is a function returning a pointer to a function returning int.

int *(*F())();

  • F is a function returning a pointer to a function returning a
    pointer to an int.

int (*F())[];

  • F is a function returning a pointer to an array of int.

int (*(*F())[])();

  • F is a function returning a pointer to an array of pointers to
    functions returning int.

int *(*(*F())[])();

  • F is a function returning a pointer to an array of pointers to
    functions returning a pointer to int.

+++Date last modified: 05-Jul-1997

Organization: KFW Corporation, Newbury Park, CA
Message-ID: <1990Jul16.195111.5976@kfw.COM>
Newsgroups: comp.lang.c

I've received several mail messages since offering to explain the
right-left rule via e-mail, so I've decided to post. For those of
you who already know this or don't care, quit now (this is a little
long).

The "right-left" rule is a completely regular rule for deciphering C
declarations. It can also be useful in creating them.

First, symbols. Read

  • as "pointer to"

[] as "array of"
() as "function returning"

as you encounter them in the declaration.

STEP 1


Find the identifier. This is your starting point. Then say to yourself,
"identifier is". You've started your declaration.

STEP 2


Look at the symbols on the right of the identifier. If, say, you find "()"
there, then you know that this is the declaration for a function. So you
would then have "identifier is function returning". Or if you found a
"[]" there, you would say "identifier is array of". Continue right until
you run out of symbols OR hit a right parenthesis ")". (If you hit a
left parenthesis, that's the beginning of a () symbol, even if there
is stuff in between the parentheses. More on that below.)

STEP 3


Look at the symbols to the left of the identifier. If it is not one of our
symbols above (say, something like "int"), just say it. Otherwise, translate
it into English using that table above. Keep going left until you run out of
symbols OR hit a left parenthesis "(".

Now repeat steps 2 and 3 until you've formed your declaration. Here are some
examples:

int *p[];

  1. Find identifier. int *p[];
    ^
    "p is"
  2. Move right until out of symbols or left parenthesis hit.
    int *p[];
    ^^
    "p is array of"
  3. Can't move right anymore (out of symbols), so move left and find:
    int *p[];
    ^
    "p is array of pointer to"
  4. Keep going left and find:
    int *p[];
    ^^^
    "p is array of pointer to int".

Another example:

int *(*func())();

  1. Find the identifier. int *(*func())();
    ^^^^
    "func is"
  2. Move right. int *(*func())();
    ^^
    "func is function returning"
  3. Can't move right anymore because of the right parenthesis, so move left.
    int *(*func())();
    ^
    "func is function returning pointer to"
  4. Can't move left anymore because of the left parenthesis, so keep going
    right. int *(*func())();
    ^^
    "func is function returning pointer to function returning"
  5. Can't move right anymore because we're out of symbols, so go left.
    int *(*func())();
    ^
    "func is function returning pointer to function returning pointer to"
  6. And finally, keep going left, because there's nothing left on the right.
    int *(*func())();
    ^^^
    "func is function returning pointer to function returning pointer to int".

As you can see, this rule can be quite useful. You can also use it to
sanity check yourself while you are creating declarations, and to give
you a hint about where the put the next symbol and whether parentheses
are required.

Some declarations look much more complicated than they are due to array
sizes and argument lists in prototype form. If you see "[ 3]", that's
read as "array (size 3) of…". If you see "(char *,int)" that's read
as "function expecting (char *,int) and returning…". Here's a fun
one:

int (*(*funone)(char *,double))[9 ][20 ];

I won't go through each of the steps to decipher this one. It's:

"funone is pointer to function expecting (char *,double) and
returning pointer to array (size 9) of array (size 20) of int."

As you can see, it's not as complicated if you get rid of the array sizes
and argument lists:

int (*(*funone)())[][];

You can decipher it that way, and then put in the array sizes and argument
lists later.

Some final words:

It is quite possible to make illegal declarations using this rule,
so some knowledge of what's legal in C is necessary. For instance,
if the above had been:

int *((*funone)())[][];

it would have been "funone is pointer to function returning array of array of
^^^^^^^^^^^^^^^^^^^^^^^^
pointer to int". Since a function cannot return an array, but only a
pointer to an array, that declaration is illegal.

Will
will@kfw.com
uunet!charyb!will

Comments

comments powered by Disqus