C语言中的复杂声明

    大多数情况下,声明很容易读取,但是很难读取一些包含指向函数的指针的声明。例如,考虑以下来自“signal.h”的声明:

void (*bsd_signal(int, void (*)(int)))(int);

    让我们看看阅读复杂声明的步骤:
    1) 将C声明转换为后缀格式并从右向左读取。
    2) 要将表达式转换为后缀,请从最里面的圆括号开始,如果不存在最里面的圆括号,则从声明名称开始,然后向右。当遇到第一个结束括号时向左。一旦整个括号被解析,就从括号中跳出来。
    3) 继续,直到解析完整个声明。
    让我们从简单的例子开始。下面的例子来自“K&R”标准:

1) int (*fp) ();

    让我们把上面的表达式转换成后缀格式。对于上面的例子,没有最里面的括号,这就是为什么,我们将打印声明名称,即“fp”。下一步,转到表达式的右侧,但“fp”的右侧没有要解析的内容,这就是为什么转到左侧。在左侧我们找到了“*”,现在打印“*”并从括号中跳出。我们将得到如下后缀表达式:

fp  *  ()  int

    现在从左到右读后缀表达式。例如,fp是指针,指向返回int的函数。

/* Example */

#include <stdio.h>
int (*fp)();
int func(void) { printf("hello\n"); }

int main()
{
	fp = func;
	(*fp)();
	// fp(); // This will also call func
	return 0;
}

    输出:

hello

    让我们看更多的例子。

2) int (*daytab)[13]

    后缀:daytab * [13] int
    含义:daytab是指向整数数组的指针,该数组包含13个整数。

/* Example */

#include <stdio.h>
int (*daytab)[13];
int arr[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
int main()
{
	daytab = &arr;
	printf("arr[2] = %d\n", (*daytab)[2]);
	return 0;
}

    输出:

arr[2] = 3
3) void (*f[10]) (int, int)

    后缀:f[10] * (int, int) void
    含义:是一个包含10个指针的指针数组,指向返回void的函数(它有两个int类型的参数)。

/* Example */

#include <stdio.h>
void (*f[10])(int, int);
void func1(int a, int b)
{
	printf("func1 = %d, %d\n", a, b);
}
void func2(int p, int q)
{
	printf("func2 = %d, %d\n", p, q);
}
void func3(int x, int y)
{
	printf("func3 = %d, %d\n", x, y);
}
int main()
{
	f[0] = func1;
	f[1] = func2;
	f[2] = func3;
	(*f[0])(1, 2);
	(*f[1])(3, 4);
	(*f[2])(5, 6);
	return 0;
}

    输出:

func1 = 1, 2
func2 = 3, 4
func3 = 5, 6
4) char (*(*x())[]) ()

    后缀:x () * [] * () char
    含义:x是一个函数,返回指向指针数组的指针,指针数组的指针指向返回值为char的函数。

/* Example */

#include <stdio.h>
char func1() { return 'a'; }
char func2() { return 'b'; }
char func3() { return 'c'; }

char (*xarr[])() = { func1, func2, func3 };
char (*(*x())[])() { return &xarr; }

int main()
{
	printf("%c\n", ((*(x()))[0])());
	printf("%c\n", ((*(x()))[1])());
	printf("%c\n", ((*(x()))[2])());
	return 0;
}

    输出:

a
b
c
5) char (*(*x[3])())[5]

    后缀:x[3] * () * [5] char
    含义:x是一个由3个指向函数的指针组成的数组,函数返回指向5个字符的数组的指针。

/* Example */

#include <stdio.h>

typedef char charray5[5];

charray5 carr1 = { 'a', 'b', 'c', 'd', '\0' };
charray5 carr2 = { 'q', 'w', 'e', 'r', '\0' };
charray5 carr3 = { 'x', 'y', 'z', 'w', '\0' };

charray5* func1() { return &carr1; }
charray5* func2() { return &carr2; }
charray5* func3() { return &carr3; }

char (*(*x[3])())[5] = { func1, func2, func3 };

int main()
{
	printf("func1 = [%c, %c, %c, %c]\n",
		((*(x[0]))())[0][0], ((*(x[0]))())[0][1],
		((*(x[0]))())[0][2], ((*(x[0]))())[0][3]);
	printf("func2 = [%c, %c, %c, %c]\n",
		((*(x[1]))())[0][0], ((*(x[1]))())[0][1],
		((*(x[1]))())[0][2], ((*(x[1]))())[0][3]);
	printf("func3 = [%c, %c, %c, %c]\n",
		((*(x[2]))())[0][0], ((*(x[2]))())[0][1],
		((*(x[2]))())[0][2], ((*(x[2]))())[0][3]);
	return 0;
}

    输出:

func1 = [a, b, c, d]
func2 = [q, w, e, r]
func3 = [x, y, z, w]
6) int *(*(*arr[5])()) ()

    后缀:arr[5] * () * () * int
    含义:arr是一个由5个指向函数的指针组成的数组,函数返回指向函数的指针,第二个函数返回指向整数的指针。

/* Example */

#include <stdio.h>

int a = 1;
int b = 2;
int* func1() { return &a; }
int* func2() { return &b; }

int* (*funcp1())() { return func1; }
int* (*funcp2())() { return func2; }
int* (*(*arr[5])())() = { funcp1, funcp2 };

int main()
{
	printf("%d\n", *(*(*arr[0])())());
	printf("%d\n", *(*(*arr[1])())());
	return 0;
}

    输出:

1
2
7) void (*bsd_signal(int sig, void (*func)(int)))(int);

    后缀:bsd_signal(int sig, void(*func)(int)) * (int) void
    含义:bsd_signal是一个函数,它接受整数和指向函数(以整数作为参数并返回void)的指针,返回指向函数(以整数作为参数并返回void)的指针。

#include <stdio.h>

void on_sig10_exit(int u) { printf("sig10 exit\n"); }
void on_sig20_exit(int u) { printf("sig20 exit\n"); }
void default_exit(int u) { printf("default exit\n"); }
void user_default_exit(int u)
{
	printf("user default exit\n");
}

void (*exit_by)(int);

void (*bsd_signal(int sig, void (*func)(int)))(int)
{
	switch (sig) {
	case 10:
		return on_sig10_exit;
	case 20:
		return on_sig20_exit;
	default:
		if (func == NULL)
			return default_exit;
		else
			return user_default_exit;
	}
}

int main()
{
	(bsd_signal(10, NULL))(0);
	(bsd_signal(20, NULL))(0);
	(bsd_signal(30, NULL))(0);
	(bsd_signal(30, user_default_exit))(0);
	return 0;
}

    输出:

sig10 exit
sig20 exit
default exit
user default exit

    (从第4个开始我就跟不上了,实际工程中会使用这么复杂的声明吗,是不是太难理解了?我有丶怀疑。)

参考文档

[1]Narendra Kangralkar.Complicated declarations in C[EB/OL].https://www.geeksforgeeks.org/complicated-declarations-in-c/,2021-03-05.

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值