• C和指针 第13章 高级指针话题 13.2 高级声明


    13.2 高级声明
        高级的指针类型是如何声明的。前面的章节介绍了表达式声明的思路以及C语言的变量是如何通过推论进行声明。还有第8章声明指向数组的指针时已经看到过一些推论声明的例子。现在通过观察一系列越来越复杂的声明进一步探索这个话题。
        几个简单的例子如下:
        int f; /*一个整型变量*/
        int *f; /*一个指向整型的指针*/
        第2个声明是如何工作的:它把表达式*f声明为一个整数。根据这个事实,肯定能推断出f是个指向整型的指针。C声明的这种解释方法可以通过下面的声明得到验证:
        int* f, g;
        它并没有声明两个指针。尽管它们之间存在空白,但星号还是作用于f的,只有f才是一个指针。g只是一个普通的整型变量。
        int f();
        f声明为一个函数,它的返回值是一个整数。旧式风格的声明对函数的参数并没有提供任何信息。它只声明f的返回值类型。现在将使用这种旧式风格,这样例子看上去简单一些,后面再回到完整的原型形式。
        int *f();
        要想推断出它的含义,必须确定表达式*f()是如何进行求值的。首先执行的是函数调用操作符(),因为它的优先级高于间接访问操作符。因此f是一个函数,它的返回值是一个指向整型的指针。
        如果“推论声明”看上去有点讨厌,只要这样考虑就可以了:用于声明变量的表达式和普通的表达式在求值时所使用的规则相同。我们不需要为这类声明学习一套单独的语法。如果能够对一个复杂表达式求值,同样可以推断出一个复杂声明的含义,因为它们的原理是相同的。
        接下来的一个声明更为有趣:
        int (*f)();
        确定括号的含义是分析这个声明的一个重要步骤。这个声明有两对括号,每对的含义各不相同。第2对括号是函数调用的操作符,但第1对括号只起到聚组的作用。它迫使间接访问在函数调用之前进行,使f成为一个函数指针,它所指向的函数返回一个整型值。函数指针?是的,程序中的每个函数都位于内存中某个位置,所以存在指向那个位置的指针是完全可能的。
        int *(*f)();
        它和前一个声明基本一样,f也是一个函数指针,只是所指向的函数的返回是一个整型指针,必须对其进行间接访问操作才能得到一个整型值。
        把数组也考虑进去:
        int f[];
        这个声明表示f是个整型数组。数组的长度暂时忽略,因为我们现在关心的是它的类型,而不是它的长度。
        如果它们的链接属性是external或者是作用于函数的参数,即使它们在声明时未注明长度,也仍然是合法的。
        int *f[];
        这里出现了两个操作符。下标的优先级更高,所以f是一个数组,它的元素类型是指向整型的指针。
        下面这个例子隐藏着一个圈套。不管怎样,让我们先推断出它的含义。
        int f()[];
        f是一个函数,它的返回值是一个整型数组。这里的圈套在于这个声明是非法的---函数只能返回标量值,不能返回数组。
        这里还有一个例子,颇费思量。
        int f[]();
        现在,f似乎是一个数组,它的元素类型是返回值为整型的函数。这个声明也是非法的,因为数组元素必须具有相同的长度,但不同的函数显然具有不同的长度。
        但是,下面这个声明是合法的:
        int (*f[])();
        首先,必须找到所有的操作符,然后按照正确的次序执行它们。同样,这里有两对括号,它们分别具有不同的含义。括号内的表达式*[]首先进行求值。所以f是一个元素为某种类型的指针的数组。表达式末尾的()是函数调用操作符,所以f肯定是一个数组,数组元素的类型是函数指针,它所指向的函数的返回值是一个整型值。
        如果大家搞清楚了上面最后一个声明,下面这个应该是比较容易的了:
        int *(*f[])();
        它和上面那个声明的唯一区别就是多了一个间接访问操作符,所以这个声明创建了一个指针数组,指针所指向的类型是返回值为整型指针的函数。
        到目前为止,这里使用的是旧式风格的声明,目的是为了让例子更简单一些。但是ANSI C要求我们使用完整的函数原型,使声明更为明确。例如:
        int (*f)( int, float );
        int *(*g[])( int, float );
        前者把f声明为一个函数指针,它所指的函数接受两个参数,分别是一个整型值和浮点型值,并返回一个整型值。后者把g声明为一个数组,数组的形式是一个函数指针,它所指向的函数接受两个参数,分别是一个整型值和浮点型值,并返回一个整型指针。尽管原型增加了声明的复杂程度,但我们还是应该提倡这种风格,因为它向编译器提供了一些额外的信息。
        提示:
        如果大家使用的是UNIX系统,并能访问Internet,则可能获得一个名叫cdecl的程序,它可以在C语言的声明和英语之间进行转换。它可以解释一个现存的C语言声明:
           int (*(*f)())[10]; /* f as pointer to function returning pointer to array 10 of int. */
        或者给出一个声明的语法:
        /* x as pointer to array to array 10 of pointer to function returning int. */
        int (*(*x)[10])(); 
        cdecl的源代码可以从comp.sources.unix.newsgroup存档文件第14卷中获得。 (真的有源码呢!感兴趣自己可以去看看呢。)

    /*
    ** 高级声明。 
    */
    #include <stdio.h>
    #include <stdlib.h>

    int main( void ){
        int f; /* an integral variable */ 
        int *f; /* a pointer points to an int */
        int *f, g; /* f is a pointer points to an int, g is an int */
        int f(); /*f is a function name, the return value of function is an int. This is an old style */
        int (*f)(); /* f is a pointer points to a function, the return value of function is an int */
        int *(*f)(); /* f is a pointer points to a function, the return value of function is a pointer points to an int */
        int f[]; /* here, we omit the length of array, because we care the type of array. f is an integral array. */
        int *f[]; /* the priority of [] operator is higher than the * operator, so executes [] operation firstly. f is an
        array, every element in array is an int */
        int f()[];     /* In terms of priority, f should be a function, the return value of function is an array, but it is 
        illegal actually, because c standard stipulates the function can't return an array. */
        int f[](); /* In terms of priority, f should be an array, the return value of array is a function, but it is also
        illegal actually, because every element in array must have the same length, but different function may have diff-
        erent length obviously. */
        int (*f[])(); /* f is an array, every element in array is a pointer points to a function, the return value of 
        function is an int. */
        int *(*f[])(); /* f is an array, every element in array is a pointer points to a function, the return value of 
        function is a pointer points to an int. */
        /* ANSI C requests we must use function prototype. */
        int (*f)( int, float ); /* f is a pointer points to a function, this function receives two parameters, one is 
        an int, the other is a float, the return value of function is an int. */
        int *(*g[])( int, float ); /* g is an array, every element in array is a pointer points to a function, this function
        receives two parameter, one is an int, the other is a float, this return value of function is a pointer points to
        an int. */
        int (*(*f)())[10]; /* f as pointer to function returning pointer to array 10 of int. */
        int (*(*x)[10])(); /* x as pointer to array to array 10 of pointer to function returning int. */
         
        return EXIT_SUCCESS;
    }
     

  • 相关阅读:
    vue如何实现多页面应用网页
    VSCode 常用配置
    【Arduino+ESP32专题】案例:串口接收字符串并按指定分隔符分割
    Maven setting配置文件
    html 隐藏广告代码,Javascript实现关闭广告实现删除广告的效果
    初识贝塞尔(bezier)曲线
    CentOS7的#!bash #!/bin/bash #!/bin/env bash #!/usr/bin/bash #!/usr/bin/env bash
    操作系统(六)| 文件系统下 文件使用 共享 保护
    mysqldump和XBK备份
    【五天时间】Qt从入门到实战:第三天
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/125551409