UP | HOME

C语言复杂声明分析

目录

const 与指针

C 语言中的声明可能会带来严重的问题,尤其是当声明又长又晦涩的时候,很容易就会把新手程序员搞的不知东南西北。虽然说 C 语言的声明语法对编译器来说并不是什么复杂的事,但是对于一般的程序员来说却是晦涩难懂、难以理解。C语言的声明所存在的一个最大的问题是你无法以一种人们所习惯的从左到右的自然方式来阅读一个声明。

比如包含 const 和指针的以下几种情况的声明:

    const int * pointer;
    int const * pointer;
    int * const pointer;

在前两种情况中,表示指针所指向的对象是只读的,而在最后一种情况中,表示指针本身是只读的。 如果指针指向的对象和指针本身都是只读的话,下面这两种方法都可以做到这一点:

    const int * const pointer;
    int const * const pointer;

也就是说 const 关键字在 int 的左边还是右边是没有区别的,只有当 const 位于指针星号的右边的时,才作用于指针本身。


优先级规则

但是当声明特别复杂的时候,比如 char ( c[10])(int **p),该怎么办呢?由于我们无法从左到右以一种自然的方式来解读声明,所以就需要用到声明的优先级规则了:

    A. 声明从它的名字开始读取,然后按照优先级顺序依次读取。
    B. 优先级从高到低依次是:
        1. 声明中被括号括起来的那部分
        2. 后缀操作符:括号()表示这是一个函数,而方括号[]表示这是一个数组。
        3. 前缀操作符:星号*表示“指向…的指针”。
    C. 如果const或volatile关键字的后面紧跟类型说明符(如果int, long等),那么它作用于类型说明符。在其他情况下,const或volatile关键字作用于它左边紧邻的星号。

所以如果我们用上面的优先级规则来分析的话,可以得到:c是一个 10 个元素大小的数组,它的元素类型是函数指针且该函数有一个类型为整型的指向指针的指针的参数,其所指向的函数返回一个 char 类型的指针。

再来一个例子,char * const *(*next)(),next 是一个函数指针,该函数返回另一个指针,该指针又指向一个类型为 char 的常量指针。


typedef 声明

如果声明中包含 typedef 定义的名字,我们可以使复杂的声明稍作简化。比如,我们来分析一下 signal()函数,其声明如下:

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

我们可以使用 typedef 来在应用 signal 函数的时候将其简化

    typedef void (*ptr_to_func) (int);
    /*
     *它表示ptr_to_func是一个函数指针,
     *该函数接受一个int参数,返回值为void
     */

    ptr_to_func signal(int, ptr_to_func);
    /*
     *它表示signal是一个函数,它接受两个参数,
     *其中一个是int,另一个是ptr_to_func,返回
     *值是ptr_to_func。
     */

然而虽然 typedef 能够在一定程度上简化,但是也同样的具有与其他声明一样的混乱语法。尽量不要为了方便而对结构使用typedef。

作者: Petrus.Z

Created: 2021-09-01 Wed 00:38