对
0. 如何理解
不过如果要更加系统化地理解C的类型表达式,可以使用下面的方法
一个声明本身可以看作是一个不断嵌套括号的“表达式”,例如int a[10][10]这个语句,其实它的构成是:编译器在遍历抽象语法树的时候是这么考虑的:
1. 首先,令x1 =(((a)[10])[10]),这时相当于int x1;x1的类型是int,记作x1.type = int。
2. 接着,领x2 = ((a)[10]),这时有x1 = x2[10];这说明x2是一个长度为10,元素类型为x1.type的数组,其类型x2.type = array(10, x1.type) = array(10, int);
3. 然后,令x3 = a,则有x2 = x3[10];则有x3.type = array(10, x2.type);代入2)中的结果得:x3.type = array(10, array(10, int))。
其中,array(length, type)表示一个长度为length,元素类型为type的数组类型。
用递归方法表示就是:
1)a.type = array(10, t1)
2)t1 = array(10, t2);
3)t2 = int
1. 举一反三
那么好了,用这个方法,我们可以解释相当一部分很难理解的类型,例如这个诡异的声明语句:int (*(x[10]))(char, char) 这是个什么鬼呢?首先,我们按照层次顺序来看:
1)x1 = (*(x[10]))(char, char);这时候声明等价于int x1;说明x1.type = int;
2)x2 = (*(x[10]));这时由x1 = x2(char, char),说明x2是一个返回类型为x1.type,输入两个char类型参数的函数,我们记作x2.type = func(x2.type, [char, char]);代入x1.type得到:x2.type = func(int, [char,char]);
3)x3 = (x[10]);这时候有x2 = *x3,说明x3是指向x2类型的指针,因此x3其实就是个函数指针啦!有:x3.type = ptr(x2.type) = ptr(func(int, [char,char]))
4)x4 = x;这时候有x3 = x4[10],说明x4是一个指向x3类型的长度为10的数组,即:x4.type = array(10, x3.type) = array(10, ptr(func(int, [char,char])))
那么x的类型是什么呢?用自然语言说起来有点绕口,那就是:
1)x是一个长度为10的数组,它的元素类型为t1;
2)类型t1是一个指针类型,t1指针内容的类型为t2;
3)类型t2是一个函数类型,该函数输入两个char类型参数,返回类型为t3;
4)类型t3为int
2. 如何使用?
声明一个复杂类型的变量容易,但是能合法地使用并不是很简单。以章节1部分的那个声明为例:int (*(x[10]))(char, char) 这个变量的一个合法使用是:x[1]('a', 'b')
怎么理解这个表达式?也是按照层次来分析:
1)首先x[1],由于x.type = array(10, ptr(func(int,[char,char])))),
因此x[1]的类型是ptr(func(int, [char, char])),即一个指向函数的指针,指向的函数接收两个char类型值,返回int类型。
2)接着(x[1])('a','b'),相当于在x[1]的类型上再调用一次函数,由于x[1]是一个函数指针,因此可以直接作为函数调用,它接受了两个字符输入,因此这个表达式其实就是一个函数调用!
那么简单的如何解释呢?
x[1]首先获取x数组位置1的函数指针;
接着用参数('a','b')调用x[1]所指向的函数;
最后,调用完成后,返回这个函数在('a','b')下的返回值。
3. 应用
在弄明白了C语言这些声明语句的层次关系后,现在请设计一个函数表类型,这个函数表输入函数名称,返回一个该函数名称的重载函数列表的指针;这些函数都有相同的声明形式,如下:在C++中,这么声明(本人没尝试过,哪位闲着无聊可以试一下能不能通过编译。。。):
using namespace std;
map func_map;
例如,当我要使用名称为“compare_100”函数名的函数列表时,通过:auto list = func_map["compare_100"]; 接着,我们选取这个list的第一个函数指针最后,调用该函数:auto retval = fptr(x, y);
当然你也可以一步写完:auto retval = func_map["compare_100"][0](x, y); 4. 用C写函数式编程范式程序
最后各位可以试一下下面这个定义声明,是不是能通过编译?理解一下它神马意思?int (*(select_function(char *))(char, char)); 给你们一点提示,下面是使用这个变量select_function的例子:auto fptr = select_function("min_char");
auto a_b_min = fptr('a', 'b'); 是不是有点像函数式编程范式?根据名称返回一个函数?
顺带一提,这可都是用纯C/C++语法写出来的哟,没借助什么函数编程范式的特有语法哦╮(╯▽╰)╭
PS:上面的声明我没有试着用VS测试过,如果有错的话请轻喷=A=!
PPS:当年硕士项目组的静态分析器我们就是这么识别变量类型的,如果这些声明有错,那,那我反正是不负责啦(怒摔)! |