美文网首页
5.12复杂声明(上)

5.12复杂声明(上)

作者: Hy_Slin | 来源:发表于2018-02-11 14:06 被阅读0次

    这章的复杂声明我并没有想去深入的研究,暂时,只要能看懂,稍微用一些有用的部分即可.因为这个复杂声明实在是复杂的过分.而且对于可读性来说简直是破坏性的.有可能自己之后去看都不知道是什么意思.这个只等我之后需要提高的时候再来深入研究.
    这个复杂声明实在是不好解释,我在这里还是摘网上的一些高人写的总结比较好.


    在c言语的复杂类型声明中,我们用到3个修饰符:*、()、[]。含义如下:

    • 暗示声明一个指针
      () 暗示声明一个函数
      [] 暗示声明一个数组
      c语言允许我们一次使用多个上面所说明的修饰符来申明一个变量,这样我们可以构造出多种多样的类别来。
      大家先看下面的例子:
      int board[8][8]; //二维数组(一个8个元素的数组,元素内容还是数组)
      int *p; //指向指针的指针(一个指针,内容还是一个指针)
      int array[10]; //10个元素的数组,元素内容是指针。
      int (
      p)[10]; //一个指针,指向含有10个元素的数组。
      int oof[3][4]; //3个元素的数组,存放的内容是指针,指针分别指向4个元素的数组
      int (
      oof)[3][4]; //一个指针指向3
      4 的数组。

    看到这里,可能有人会想,你在说些什么哦,怎么看不明白,没有关系,看完下面的3条法则,你在来看上面的内容就很清晰了。
    1:离名字越近的修饰符优先级越高
    2:[],()优先级比*高
    3:用()括起来的表达式的优先级最高。

    我用这些法则来解释上面提到的例子,请看
    int *foo[3][4]

    名字:foo

    、[3] 离名字一样近,而[4]离的比他们远,所以、[3]的优先级比[4]高。(法则1)
    而 [] 的优先级比*高 (法则2)
    优先级关系如下:
    [3] > * > [4]

    所以int foo[3][4] 是一个3个元素的数组(第一个修饰符[3]),存放内容是指针(第二个修饰符号),指针分别指向4个元素的数组(第三个修饰符[4])

    int (*foo)[3][4]
    名字:foo
    优先级关系如下:(括号括起来的表达式优先级最高)

    • [3] > [4]
      所以一个指针指向3*4 的数组。


    先从最简单的开始,逐步加深:
    int (func)(int p);
    首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个
    号,这说明func是一个指针,然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(
    func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int类型的形参,返回值类型是int。
    int (
    func)(int p, int (f)(int));
    func被一对括号包含,且左边有一个
    号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有int 和int ()(int)这样的形参,返回值为int类型。再来看一看func的形参int (f)(int),类似前面的解释,f也是一个函数指针,指向的函数具有int类型的形参,返回值为int。
    int (func[5])(int p);
    func右边是一个[]运算符,说明func是一个具有5个元素的数组,func的左边有一个
    ,说明func的元素是指针,要注意这里的
    不是修饰func的,而是修饰func[5]的,原因是[]运算符优先级比高,func先跟[]结合,因此修饰的是func[5]。跳出这个括号,看右边,也是一对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int类型的形参,返回值类型为int。
    int (
    (func)[5])(int p);
    func被一个圆括号包含,左边又有一个
    ,那么func是一个指针,跳出括号,右边是一个[]运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个
    号,说明这个数组的元素是指针,再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int形参,返回值为int类型的函数。
    int (
    (*func)(int p))[5];
    func是一个函数指针,这类函数具有int
    类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。
    要注意有些复杂指针声明是非法的,例如:
    int func(void) [5];
    func是一个返回值为具有5个int元素的数组的函数。但c语言的函数返回值不能为数组,这是因为如果允许函数返回值为数组,那么接收这个数组的内容的东西,也必须是一个数组,但C语言的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能为数组。
    int func5;
    func是一个具有5个元素的数组,这个数组的元素都是函数。这也是非法的,因为数组的元素除了类型必须一样外,每个元素所占用的内存空间也必须相同,显然函数是无法达到这个要求的,即使函数的类型一样,但函数所占用的空间通常是不相同的。


    一、“right-left”规则
    看过《C专家编程》中的分析规则,用起来并不是很舒服,遂在网上寻找,发现还有一个著名的“right-left”规则。规则经翻译总结后如下:

    “right-left”规则:

    1. 规则中符号
    • 读作 “指向...的指针”
      [] 读作 “...的数组”
      () 读作 “返回...的函数”
    1. 起始点
      找到声明中的标识符(Identifier),它就是你分析的起始点,读作:“$(Identifier)是...”;

    2. 右边
      看你的标识符右边
      a) 如果发现“()”,你将知道这是一个函数声明,这时你可以说“$(Identifier)是返回...的函数”;
      b) 如果发现“[]”,你将知道这是一个数组声明,这时你可以说“$(Identifier)是...的数组”;
      c) 继续向右,直到遇到右边声明结束或者遇到“)”,继续下面。

    3. 左边
      看你的标识符左边
      a) 如果碰到的不是我们在0.中定义的符号,则直接说出它;否则按照0.中定义的符号含义说出。继续向左,直到遇到左边声明结束或“(”。

    4. 重复2和3的步骤,直到声明分析完毕。

    二、例子详解
    我们从简单到复杂,循序渐进。
    [Example 1] int *p[];

    1. 找到标识符:p,读作:“p是...”;
    2. 向右看:发现一“[]”,然后遇到右边声明结尾,读作:“p是...的数组”;
    3. 向左看:发现一“*”, 读作:“p是指向...的指针的数组”;
    4. 继续向左看:没有发现0.中定义的符号,则分析结束,读作:“p是指向int类型的指针的数组”。

    [Example 2] int (func())();

    1. 找到标识符:func,读作:“func是...”;
    2. 向右看:发现一“()”,然后遇到“)”,读作:“func是返回...的函数”;
    3. 向左看:发现一“*”,然后遇到“(”,读作:“func是返回指向...的指针的函数”;
    4. 向右看:发现一“()”,然后右边声明结束,读作:“func是返回指向返回...的函数的指针的函数”;
    5. 向左看:发现一“*”,读作:“func是返回指向返回指向...的指针的函数的指针的函数”;
    6. 向左看:没有发现.中定义的符号,则分析结束,读作:“func是返回指向返回指向int类型的指针的函数的指针的函数”。

    相关文章

      网友评论

          本文标题:5.12复杂声明(上)

          本文链接:https://www.haomeiwen.com/subject/fisrkxtx.html