如何阅读 C 语言的声明

众所周知,C 语言的一大难点就在于变量声明。 比如说如下的几个例子:

  • char* const *(*next)();
  • char *(*c[10])(int **p);
  • void (*signal(int, void(*)(int)))(int);

基本上每一个都是晦涩难懂,看了简直像杀人。但其实也是相对来会所比较简单的一个。如果熟悉编译原理,其实可以通过人脑编译器的手段来解决难懂问题。毕竟,代码也需要编译器进行翻译。

首先我们得知道运算符号的优先级顺序。这里只说在声明期间会出现的符号。主要分为变量名,括号内内容,后缀操作符如:[], ()前缀操作符如: *,类型描述符如:const, volatile, 其中, 如果 const 或 volatile 后面跟着类型如 int, long 等,那么它作用于类型。其他情况下,const 和 volatile 作用于左边的指针

理解了这个顺序,就可以来看看如何解读第一个声明了。

  1. 首先,next 先拿出来,说明,next 是一个 … 变量。声明变成了 char* const *(*)();
  2. 然后看到 *,说明 next 是一个指向 … 的指针。声明变成了 char* const *();
  3. 然后就是 ()符号,说明 next 是一个指向函数的指针。然后再是一个 * 表明读取指针的内容即该函数地址。所以声明等价于 char* const func();
  4. 那么接着看,char* const 就表示返回值是一个 const 字符指针。
  5. 所以该声明就能读出来了。即 next 是一个函数指针,该函数返回值是一个 const 字符指针。

再来看看第二个声明:

  1. 首先 c 先拿出来,一看有后缀操作符,那就直接拿出来 c[10],说明 c 是一个大小为 10 的数组。声明变成了 char *(*)(int**p);
  2. 然后可以看到有一个指针操作符,那就可以看成,c 是一个大小为 10 的数组,内容是指针。声明变成了 char *()(int **p);
  3. 因为可以看到紧跟的是一个后缀操作符,可以知道,这是一个函数,它接受的参数是一个指向 int 的指针的指针(可以理解为二维数组)。
  4. 往前就是一个 * 号,表示读取该指针的内容,最前面的 char 表示该函数的返回值是字符。
  5. 所以,最后这个声明也能看出来了:c 是一个大小为 10 的数组,数组的类型是一个指向函数的指针,该函数接受一个指向 int 的指针的指针,返回值是 char。

最后就可以看最后的一个声明了。

  1. 首先拿出来 signal ,紧跟着是一个后缀操作符,所以可以读作 signal 是一个函数,他接受的参数是一个 int 和一个返回值为 void 接受参数为 int 的函数指针。
  2. 声明变成了 void (*)(int);,是不是突然就简单了。这个就可以读作一个指向函数的指针,该函数返回值为 void 参数为 int。
  3. 所以最后的声明也就出来了。signal 是一个函数指针,它指向的函数读入的参数为 int 和一个返回值为 void 接受参数为 int 的函数指针,指向的函数的返回值也是一个返回值为 void 参数为 int 的函数指针。
  4. 虽然有点拗口,但是实际使用的时候,其实也很简单。
#include "signal.h"
#include "stdio.h"
#include "sys/signal.h"

void f(int a)
{
	printf("%d", a);
}


int main(int argc, char *argv[])
{
	void (*sfp)(int);
	sfp = f;
	signal(SIGINT, sfp);
	int a;
	scanf("%d", &a);
	return 0;
} 

这样的话其实就完成了一个绑定。在这个例子里,你可以通过 ctrl + c 来触发一个 SIGINT 信号。然后系统会自动的执行那个回调函数。当然你也可以手动触发这个函数:(*signal(SIGINT, sfp))(2);, 当然,通常情况是,异常退出。

以上就是刚看完的一个理解声明的方法以及几个简单的实例。不得不说,和其他严格限制程序员想象力的高级语言不同。C 只定义了简单的规则,然后留有大片的空间可供发挥。非常喜欢这个。

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.