当前位置: C语言 -- 专题 -- 读懂C语言声明

读懂C语言声明

声明(declaration)指定了标识符的解释和属性。本文将在C语言简单声明的基础上讲述如何读懂复杂的C声明。


一、简单声明

1、普通声明

int a;      
double b;

标识符a表示int类型变量;标识符b表示double类型变量。


2、与指针有关的声明

int *ptr;      
int **pptr;

标识符ptr表示指向int类型对象的指针。标识符pptr表示指向指针的指针,其指向的指针指向一个int类型对象。


3、与数组有关的声明

int a[5]; 
double * b[3];

标识符a表示一个有5个数组元素的数组,每个数组元素都是int类型对象。标识符b表示一个有3个数组元素的数组,每个数组元素都是指向double类型对象的指针。


#define N 5
...
int arr[N];

arr表示一个定长数组,在程序编译时确定数组大小。


int n;
...
int arr[n];

arr表示一个变长数组(variable length array),在程序执行时确定数组大小。


extern int arr[];

arr表示一个未指定大小的数组,是一种不完整类型(incomplete type);这里只是声明了标识符arr,并没有为其分配存储空间;程序还应该在其它位置定义arr,为其分配存储空间。


4、与函数有关的声明

函数类型由其返回值类型和参数的数量、类型共同决定。

int f(void);
int * func();
int (*ptr)();

标识符f表示无参数、返回int类型值的函数;关键词void如果出现在参数位置表示无参数,如果出现在返回值位置表示无返回值,如果用于指针,则表示通用指针。标识符func表示无参数、返回一个指针的函数,返回的指针指向int类型对象。如果()内为空,则表示无参数;如果存在参数,函数声明至少应给出参数的类型;如果存在多个参数,不同参数之间应使用,进行分割。标识符ptr表示一个指针,该指针指向一个无参数、返回int类型值的函数。(*ptr)中的()不能省略,如果省略,标识符ptr表示无参数、返回一个指针的函数,返回的指针指向int类型对象。


int f(int a, double b);
int func(int, double);

标识符f和标识符func均表示有2个参数(一个是int类型,另一个是double类型。)、返回int类型值的函数。

:关于C语言中完整的声明规则可参阅ISO/IEC 9899:2018标准第6.7 Declarations节。


二、复杂声明

复杂声明的理解可遵循以下两个规则:

1、从标识符开始,由内向外;

2、在同一层次上,由右向左。如果右侧存在[],则表示数组;如果右侧存在(),则表示函数;如果左侧存在*,则表示指针。


接下来使用上述规则解释3个复杂声明。

int (*arr[3])(int, double);

在这个声明中标识符是arr,由内向外红色部分是第1层,蓝色部分是第2层。

在红色部分,标识符arr右侧存在[3],左侧存在*,所以标识符arr表示有3个数组元素的数组,每个数组元素都是一个指针。

蓝色部分表示指针指向的对象,右侧存在(int, double)表示这是一个函数指针,所以指针指向的是一个有2个参数(一个是int类型,另一个是double类型。)、返回值为int类型的函数。

综上所述,标识符arr表示有3个数组元素的数组,每个数组元素都是一个指针,指向一个有2个参数(一个是int类型,另一个是double类型。)、返回值为int类型的函数。


char (*(*func())[])();

在这个声明中标识符是func,由内向外红色部分是第1层,蓝色部分是第2层,绿色部分是第3层。

在红色部分,标识符func右侧存在(),左侧存在*,所以标识符func表示一个无参数,返回指针的函数。

蓝色部分表示函数返回指针指向的对象,右侧存在[],表示这是一个数组,左侧存在*,表示数组元素是指针,所以函数返回指针指向的是数组元素为指针的数组。

绿色部分表示数组元素指向的对象,右侧存在(),表示这是一个函数,所以数组元素是函数指针,指向无参数、返回值类型为char类型的函数。

综上所述,标识符func表示一个无参数,返回指针的函数;返回的指针指向数组元素为指针的数组;数组元素为指向无参数、返回值类型为char类型的函数的指针。


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

这是ISO/IEC 9899:2018标准<signal.h>头文件中声明的signal函数。在这个函数中存在三个标识符:signalsigfunc;其中sigfunc表示的形式参数名,在声明中是可以省略的,所以这个声明应从标识符signal开始,由内向外红色部分是第1层,蓝色部分是第2层。

在红色部分,标识符signal右侧存在(int sig, void (*func)(int)),左侧存在*,所以标识符signal表示有两个参数(一个是int类型整数,另一个是指向有一个int类型参数、无返回值的函数的指针。)、返回指针的函数。

蓝色部分表示函数返回指针指向的对象,右侧存在(int)表示这是一个函数,左侧存在void,表示该函数无返回值,所以函数返回指针指向有一个int类型参数、无返回值的函数。

综上所述,标识符signal表示有两个参数(一个是int类型整数,另一个是指向有一个int类型参数、无返回值的函数的指针。)、返回指针的函数;返回的指针指向有一个int类型参数、无返回值的函数。


主要参考资料:

1、ISO/IEC 9899:2018

2、C程序设计语言》第2版 作者:BRIAN W. KERNIGHAN DENNIS M. RITCHIE 出版社:机械工业出版社

3、learn.microsoft.com : Interpreting More Complex Declarators