引言:经常在一些社区上看到莫名的一句话
PHP是世界上最好的语言
,在语言的争论上,确实是大有华山论剑
的门派之争。本文将通过编程语言的范式
角度,来了解整个编程语言的发展史,同时更清晰的认知编程范式
,以达到知己知彼,百战不殆
编程语言发展到今天,出现了好多不同的代码编写方式,但不同的方式解决的都是同一个问题,那就是如何写出更为通用、更具可重用性的代码或模块。
一、从C语言谈起
C语言的历史悠久,自其问世以来,其影响了太多太多的编程语言,到现在还一直被广泛使用,不得不佩服它的生命力。但是,我们也要清楚的知道,大多数的使用C语言来做内核的编程语言其实都是在改善C语言带来的问题+时代发展带来的变化。
下面来简单回顾下C语言的特性:
- C 语言是一个静态弱类型语言,在使用变量时需要声明变量类型,但是类型间可以有隐式转换;
- 不同的变量类型可以用结构体(struct)组合在一起,以此来声明新的数据类型;
- C 语言可以用 typedef 关键字来定义类型的别名,以此来达到变量类型的抽象;
- C 语言是一个有结构化程序设计、具有变量作用域以及递归功能的过程式语言;
- 通过指针,C 语言可以容易地对内存进行低级控制,然而这加大了编程复杂度;
- 编译预处理让 C 语言的编译更具有弹性,比如跨平台。
然而,在代码组织和功能编程上,C语言的上述,却不那么美妙了,eq:
//一个简单的交换两个变量的函数
void changeVar(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
可以想一想,这里为什么要用指针呢?因为如果不用指针的话,只是传进来的行参,即函数的形参是调用实参的一个拷贝,函数闭包里对形参的修改无法影响实参的结果。
然而,这个函数最大的问题是int tmp = *x
决定了这个函数只能给int值使用,但是还有好多类型也等着能被调用呢,eq:double、float、string等,这就是个静态语言最糟糕的问题。
当然,这个时候大家都会想到类型转换,然而对于C语言的类型转换,是会出现很多问题的。
- 比如:一个 double a[10] 的数组,a[2] 意味着 a + sizeof(double) * 2。如果你把 a 强转成 int,那么 a[2] 就意味着 a + sizeof(int) * 2。我们知道 sizeof(double) 是 8,而 sizeof(int) 是 4。于是访问到了不同的地址和内存空间,这就导致程序出现严重的问题。下面这种使用临时交换数据的buffer拷贝方案可以去掉类型转换时导致的地址变换:
//加入泛型变量的交换两个变量的函数
void changeVar(void* x, void* y, size_t size)
{
char tmp[size]; //交换数据时需要用的 buffer
memcpy(tmp, y, size);
memcpy(y, x, size);
memcpy(x, tmp, size);
/**
* 1.函数接口中增加了一个size参数,用了 void* 后,类型被“抽象”掉了
,编译器不能通过类型得到类型的长度了,所以,需要我们手动地加上一个类型长度的标识。
2.函数的实现中使用了memcpy()函数,因为类型被“抽象”掉了,所以不能用赋值表达式了,很有可能传进来的参数类型还是一个结构体,因此,为了要交换这些复杂类型的值,我们只能使用内存复制的方法了。
*/
}
除了上面使用void* 来做泛型,在C语言中,还可以用宏定义来做泛型,不过却会带来宏的字符串替换,导致代码膨胀,导致编译出的执行文件相对较大,此处感兴趣的可以去深入学习一下。