龙空技术网

技术文章:加上自动内存管理和运算符重载,C语言就是好语言

底层技术栈 3435

前言:

如今大家对“c语言open”大体比较重视,兄弟们都需要剖析一些“c语言open”的相关知识。那么小编同时在网摘上汇集了一些有关“c语言open””的相关内容,希望我们能喜欢,大家一起来学习一下吧!

scf编译器框架的语法分析模块主要参考了C语言,它的语法跟C语言大多数时候是相同的(除了没有支持宏定义之外)。

我一直认为,C语言加上自动内存管理之后,就是一门好语言[呲牙]

1,自动内存管理,

C语言最让人吐槽的地方是它需要手动管理内存,导致很容易出现特别难查的BUG。

所以,我在scf框架的后端特意添加了一个自动内存管理模块。

malloc()之后该什么时候free(),绝对是C程序员最耗费脑细胞的一个地方,而且这种耗费重复起来没完没了。

java倒是不需要手动管理内存,但是运行速度上完全没法和C相比(慢了很多)。

对于内存的管理方面,scf框架支持两种方式:自动和手动。

所有通过scf__auto_malloc()函数申请的堆内存都是自动管理的,包括通过create关键字创建的类对象。

因为C++的new运算符还可以申请普通的数组,我在scf框架里改用了create当作创建类对象的关键字。

我个人觉得,数组这种不需要构造函数的东西,完全可以直接用calloc()创建,没必要提供另外一种方式:char* p = new char[1024]。

perl语言的失败之处,就是它给同样的功能提供了不同的语法,导致同样的代码在其他人看来跟乱码一样,从而降低了程序的可读性。

所以,我就把new降成了一个普通的标志符,而不再是一个关键字。

然后,只给类对象的创建提供了一个create关键字:它会申请对象内存,并且调用构造函数。

为了不像C++那样提供一套异常机制,我让构造函数也能返回一个int变量作为错误码。

跟C语言里广泛存在的int file_open(file_t** ppfile, ...)类似,函数的参数返回错误码,输出指针返回对象指针。

我觉得这种方式最简单明了,所以我就让create关键字可以返回两个值:一个是对象指针,一个是错误码。

例如:

class A* p;

int err;

p, err = create A();

当然错误码也可以省略,直接通过p是否为NULL来判断对象的创建情况,但这没法获得细节的出错信息。

实际上,这里也可以只让create返回一个值。因为malloc()返回的指针不可能是-1、-2、-3这样的数字,只要编译器保留-1024~0作为错误码即可,没必要非得返回两个值。

不过因为scf是一个框架,所以我还是给它添加了多个返回值的功能。

这个功能在编译器的后端实现上,还是没少费了劲的。

当然返回值是不能任意多的,因为寄存器一般只有16个,能用来传递函数参数的一般只有4-6个,所以我暂时规定:返回值最多只有4个。

不过即使这样,支持create返回2个值也足够了。

2,运算符的重载,

在函数的重载方面,我只支持了运算符和构造函数的重载。

运算符重载的最大作用,就是它可以让代码写的像数学公式一样。

代码毕竟是随着数学的发展而发展的,如果数学公式写的是x = Ab,那么代码就应该写成x = A * b,而不该写成MatMulVec(x, A, b)。

MatMulVec(x, A, b),C语言这样写是很难看的,而且它只能这样写[捂脸]

这就是运算符重载的意义。

至于构造函数,也确实不得不让它重载,否则构造时就没法传参了。

如果只能用无参构造,然后再加一行init()的话,那create关键字就可以取消了。

A* p = create A();

p->init(1, 2, 3, 4);

要是这么写的话,还不如C语言呢:

A* p = NULL;

int ret = Aopen(&p, 1, 2, 3, 4);

人家至少一行代码就写完了(而且还自带错误码),前一种写法需要2行。

我想来想去,运算符和构造函数的重载还是必须的。

至于其他的成员函数,没必要非得让编译器替程序员给它取个难看的名字:这是函数重载的本质。

看看C++编译之后的那些没人看得懂的函数名,你就知道函数重载是怎么回事了。

考虑到函数重载和虚函数在多级继承之后容易找不出具体的实现位置,我就把继承、多态都给取消了。

复数类的实现

上图是复数类的实现,__init()函数在scf框架里对应着构造函数。它的返回值是int,用于返回出错码,成功则返回0。

+=和-=这类不需要额外申请内存的运算符,返回值也是int,也是用于返回错误码。

复数类的乘法

因为乘法需要返回一个额外的结果变量,需要申请内存,所以它的返回值是2个:一个返回结果的对象指针,一个返回错误码。

main函数

不过当多个变量相加或相乘的时候,如果半截里出错了,那么错误码还是没法传递到最上层的主调函数的。

例如:c0, err = c1 + c2 + c3 + c4;

在第2个加号是出错了,那么这个错误码是没法返回到main函数的:因为每一个加号相当于一次函数调用,而运算符重载的形参只有对象指针,没有错误码。

如果形参里每个对象指针都跟随一个错误码的话,显然参数太多了,过于冗杂。

如果这个错误码由编译器框架自动添加,又与编程的所见即所得矛盾了。

程序员没法从源代码里看到这点,相当于编译器瞒着程序员在做手脚:就像C++那样,这是非常让人不爽的。

想通过运算符重载把代码写的像数学公式一样,还要照顾到出错处理时的简单明了,好像暂时没什么好办法。

莫非这里触发了热力学第二定律:不能从单一热源吸热,使之完全转化为功,而不引起其他变化?![捂脸]

毕竟数学公式没有错误码的返回问题,但代码有。

标签: #c语言open